Android InputMethodManager内存泄漏
最近通过LeakCanary检测内存泄漏,发现一个很莫名其妙的问题,截图如下所示:
从这里可以看到,InputMethodManager的mNextServedView持有了一个RecyclerView的引用,而RecyclerView则持有了IndexActivity的引用,从而导致了IndexActivity的内存泄漏。
据说这是输入法的一个bug,在LeakCanary上有个提到过这个问题(https://github.com/square/leakcanary/issues/572),但是该问题并不是一个普遍性的bug,而是部分机型上会出现。本人拿手头上的几台设备测试过,小米MIX2、小米红米5、三星Note3、三星Galaxy S7 edge、Vivo X9、Oppo R9还有一台华为设备忘记型号了,只有三星 Galaxy S7 edge上频繁出现InputMethodManager内存泄漏的问题。不得不说,谷歌的Android系统坑真是多,各种机型、各种分辨率,但是没办法,有坑我们也得一个一个去填。
查看InputMethodManager的源码可以看到以下定义:
/**
* This is the root view of the overall window that currently has input
* method focus.
*/
View mCurRootView;
/**
* This is the view that should currently be served by an input method,
* regardless of the state of setting that up.
*/
View mServedView;
/**
* This is then next view that will be served by the input method, when
* we get around to updating things.
*/
View mNextServedView;
通过LeakCanary的检测发现,发生内存泄漏时,这三者都有可能被InputMethodManager持有依赖引用,而View则一直被Activity持有引用,进而导致了Activity的内存泄漏。
那么怎么解决这个问题呢?参考了不少方案,发现还是采用反射来将这些依赖的View置空,手动切断对象的引用链最有效,具体代码如下:
public class MemoryLeakUtil {
public static void fixInputMethodMemoryLeak(Context context) {
if (context == null)
return;
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager == null)
return;
String[] viewArr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
Field field;
Object fieldObj;
for (String view : viewArr) {
try {
field = inputMethodManager.getClass().getDeclaredField(view);
if (!field.isAccessible()) {
field.setAccessible(true);
}
fieldObj = field.get(inputMethodManager);
if (fieldObj != null && fieldObj instanceof View) {
View fieldView = (View) fieldObj;
if (fieldView.getContext() == context) {
//注意需要判断View关联的Context是不是当前Activity,否则有可能造成正常的输入框输入失效
field.set(inputMethodManager, null);
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
在内存泄漏的Activity里增加:
@Override
protected void onDestroy() {
//手动切断InputMethodManager里的View引用链
MemoryLeakUtil.fixInputMethodMemoryLeak(this);
super.onDestroy();
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
安卓面试中高级安卓开发工程师总结之——如何写一份让HR主动邀请你面试的简历
简历是用人单位做人事筛选的评判标准。如何让自己的简历被更多公司HR看到,并且通过技术部简历初步审核呢? 博主这次跳槽,只投过一次8个公司(小公司)的简历。然后就再也没有主动投递过简历,仅仅把自己的简历,就收到了很多大公司的面试邀请。那么博主是怎么做的呢? 首先准备一份真实的简历。真实不代表不能包装。至于怎么包装,这是一个技术活,我后面在讲。然后最好不要选择智联,51job,这些已经过时的,人才网站。也不要用58,赶集这样普通岗位的网站。最好在拉钩,猎聘,boss投递简历。不愿意花钱在人事招聘上的公司,是不会有太高的薪资和薪资涨幅的。所以,像猎聘这些高门槛,高收费,高认证,高标准的招聘网站中的公司,很多都是比较舍得花钱寻找适合自己的人才的。同时你会发现,猎聘的大公司非常多,并且薪资给的也普遍比较高。所以,建议各位在猎聘求职,补充自己的简历,然后猎聘中猎头公司非常多,如果你不想被猎头公司骚扰,你可以设置成简历仅对公司HR可见。如果你还在职,不想自己的简历被自己的公司看到,你可以屏蔽自己的公司(也可以屏蔽掉其他公司)。 第二:如果你投递的公司是大互联网公司,那么你的简历必须真实可查。尤其是学...
-
下一篇
序列化Parcelable和Serializable的区别
Parcelable和Serializable有什么用,它们有什么差别? Parcelable和Serializable都可以实现序列化,使对象可以变为二进制流在内存中传输数据。在Android中,只要实现二者之一就可以使用Intent和Binder来传递数据。实现了Parcelable接囗的类依赖于Parcel这个类来实现数据传递,它并不是一个一般化用途的序列化机制,主要用于IPC机制下的高性能传输。 差别 来源上 Parcelable是Android提供的序列化接口,Serializable是Java提供的序列化接口。因此Parcelable只能在Android中使用,而Serializable可以在任何使用Java语言的地方使用。 使用上 Parcelable使用起来比较麻烦,序列化过程需要实现Parcelable的writeToParcel(Parcel dest, int f1ags)方法和describeContents()方法。其中describeContents()方法直接返回0就可以了。为了反序列化,还需要提供一个非空的名为CREATOR的静态字段,该字段类型是实现了...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL数据库在高并发下的优化方案