博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android InputMethodManager内存泄漏
阅读量:6683 次
发布时间:2019-06-25

本文共 2513 字,大约阅读时间需要 8 分钟。

最近通过LeakCanary检测内存泄漏,发现一个很莫名其妙的问题,截图如下所示:

img_4998a3c709bb18b0fb8781525567e775.png
内存泄漏

从这里可以看到,InputMethodManager的mNextServedView持有了一个RecyclerView的引用,而RecyclerView则持有了IndexActivity的引用,从而导致了IndexActivity的内存泄漏。

据说这是输入法的一个bug,在LeakCanary上有个提到过这个问题(),但是该问题并不是一个普遍性的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();    }

转载地址:http://jxiao.baihongyu.com/

你可能感兴趣的文章
如何用机器学习预测超售,避免美联航“暴力赶客”悲剧
查看>>
css细节(实习第1天)
查看>>
腾讯Android自动化测试实战3.1.4 Robotium的控件获取、操作及断言
查看>>
《C语言点滴》一1.5 内功修炼
查看>>
linux 怎么完全卸载mysql数据库
查看>>
Dart的HTTP请求和响应(1)
查看>>
寻找最大的K个数,Top K问题的堆实现
查看>>
自动发布工具应该具备的11个标准特征
查看>>
页面设计四大基本原则
查看>>
2016及以后的自动化测试趋势 -《测试技术六月刊》
查看>>
基于Angular创建后台数据模拟(译)
查看>>
Spring中bean配置的继承
查看>>
用JSP实现学生查询
查看>>
企业网站怎么建设
查看>>
数据库和MySQL相关面试题目
查看>>
Yii 框架学习--01 框架入门
查看>>
All Things OpenTSDB
查看>>
android 网络通信框架volly
查看>>
二分查找算法及其变种
查看>>
一个泛型冒泡排序的实现
查看>>