今天偶然看看androidx.activity包中的类,发现了ImmLeaksCleaner,看来谷歌已经发现了InputMethodManager造成的内存泄漏问题,并在ComponentActivity中通过Lifecycle机制解决这个问题,但是由于国内定制机型比较多,还是会造成泄漏,下面来看看谷歌怎么做的。

先来看看那ImmLeaksCleaner的源码。

@RequiresApi(19)

final class ImmLeaksCleaner implements LifecycleEventObserver {

private static final int NOT_INITIALIAZED = 0;

private static final int INIT_SUCCESS = 1;

private static final int INIT_FAILED = 2;

private static int sReflectedFieldsInitialized = NOT_INITIALIAZED;

private static Field sHField;

private static Field sServedViewField;

private static Field sNextServedViewField;

private Activity mActivity;

ImmLeaksCleaner(Activity activity) {

mActivity = activity;

}

@Override

public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {

if (event != Lifecycle.Event.ON_DESTROY) {

return;

}

if (sReflectedFieldsInitialized == NOT_INITIALIAZED) {

initializeReflectiveFields();

}

if (sReflectedFieldsInitialized == INIT_SUCCESS) {

InputMethodManager inputMethodManager = (InputMethodManager)

mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);

final Object lock;

try {

lock = sHField.get(inputMethodManager);

} catch (IllegalAccessException e) {

return;

}

if (lock == null) {

return;

}

synchronized (lock) {

final View servedView;

try {

servedView = (View) sServedViewField.get(inputMethodManager);

} catch (IllegalAccessException e) {

return;

} catch (ClassCastException e) {

return;

}

if (servedView == null) {

return;

}

if (servedView.isAttachedToWindow()) {

return;

}

// Here we have a detached mServedView. Set null to mNextServedViewField so that

// everything will be cleared in the next InputMethodManager#checkFocus().

try {

sNextServedViewField.set(inputMethodManager, null);

} catch (IllegalAccessException e) {

return;

}

}

// Assume that InputMethodManager#isActive() internally triggers

// InputMethodManager#checkFocus().

inputMethodManager.isActive();

}

}

@MainThread

private static void initializeReflectiveFields() {

try {

sReflectedFieldsInitialized = INIT_FAILED;

sServedViewField = InputMethodManager.class.getDeclaredField("mServedView");

sServedViewField.setAccessible(true);

sNextServedViewField = InputMethodManager.class.getDeclaredField("mNextServedView");

sNextServedViewField.setAccessible(true);

sHField = InputMethodManager.class.getDeclaredField("mH");

sHField.setAccessible(true);

sReflectedFieldsInitialized = INIT_SUCCESS;

} catch (NoSuchFieldException e) {

// very oem much custom ¯\_(ツ)_/¯

}

}

}

实际上谷歌的解决方案和网上很多方案的思路也是一样的都是通过反射将泄露的引用设置为null,因为InputMethodManager造成泄漏的原因是,mCurRootView, mServedView, mNextServedView持有的context造成activity销毁但是没有被回收造成的内存泄露,我前面提到由于国内定制机型很多,比如华为还有mLastSrvView也会造成内存泄露,所以谷歌的解决方案只是针对原生系统。

ImmLeaksCleaner 实现LifecycleEventObserver有实现了LifecycleObserver,就是通过Activity的生命周期对这些在成内存泄漏的View设置为null。

接着在ComponentActivity中注册ImmLeaksCleaner 监听Activity的生命周期,代码如下:

public ComponentActivity() {

Lifecycle lifecycle = getLifecycle();

.................................

if (19 <= SDK_INT && SDK_INT <= 23) {

getLifecycle().addObserver(new ImmLeaksCleaner(this));

}

}

可以看到当19 <= SDK_INT && SDK_INT <= 23是才会做这些处理

再来来看看LifecycleEventObserver源码

public interface LifecycleEventObserver extends LifecycleObserver {

/**

* Called when a state transition event happens.

*

* @param source The source of the event

* @param event The event

*/

void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);

}

实际上LifecycleEventObserver 就是个接口定义了onStateChanged方法,当Activity的声明周期被触发就会毁掉这个方法。前面说到谷歌的解决方案并不能解决国内的情况,所以我们可以在这个基础上做修改,代码我也就贴出来了,需要注意的是谷歌的这种方案是针对。

android leaks工具,Androidx中ImmLeaksCleaner已经解决了InputMethodManager... - 简书相关推荐

  1. 【凯子哥带你学Android】Andriod性能优化之列表卡顿——以“简书”APP为例

    这几天闲得无聊,就打开手机上的开发者模式里面的"GPU过度绘制"功能,看看别家的App做的咋样,然后很偶然的打开了"简书",然后就被它的过度绘制惊呆了,于是写了 ...

  2. android解决工具类中没有context中的问题

    有时我们需要在一个工具类中用到上下文context.当然有一个做法就是使用传递context的方法,当我们需要用全局context的时候,该怎么办呢? 其实我们应用启动的时候会启动Applicatio ...

  3. Android studio 实验过程中遇到的问题之android.support.v7.app.AppCompatActivity不能使用的解决办法

    android.support.v7.app.AppCompatActivity不能使用的解决办法 在构建项目时使用 android.support.v7.XX android.support.v4. ...

  4. IOS-内存泄漏检测工具Instruments中的Leaks

    Instruments 的介绍: Instruments 是一个很灵活的.强大的工具:是性能分析.动态跟踪 和分析OS X 以及iOS代码的测试工具:用它可以极为方便收集关于一个或多个系统进程的性能和 ...

  5. android百度地图覆盖物异步加载图片,Android 百度地图marker中图片不显示的解决方法(推荐)...

    目的: 根据提供的多个经纬度,显示所在地的marker样式,如下: 问题: 1.发现marker中在线加载的图片无法显示出来: 2.获取多个对象后,却只显示出了一个marker: 以下为官网实现方法: ...

  6. Android中怎样在工具类中获取Context对象

    场景 Android程序中访问资源时需要提供Context,一般来说只有在各种component中(Activity, Provider等等)才能方便的使用api来获取Context对象, 如果在编写 ...

  7. Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)...

    当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...

  8. 安卓(android)建立项目时失败,出现Android Manifest.xml file missing几种解决方法?(总结中)

    安卓(android)建立项目时失败,出现Android Manifest.xml file missing几种解决方法?(总结中) 参考文章: (1)安卓(android)建立项目时失败,出现And ...

  9. 解决Android Studio安装过程中“SDK tools directory is missing”的问题

    解决Android Studio安装过程中"SDK tools directory is missing"的问题 参考文章: (1)解决Android Studio安装过程中&qu ...

最新文章

  1. 一张图带你了解 Spring Cloud 微服务架构!
  2. 多线程join(加入)
  3. 我们遇到什么困难都不要怕,微笑着面对它
  4. 使用PHP将HTTP标头设置为UTF-8
  5. mac找不到mysql数据库_mac下mysql升级后找回丢失数据库
  6. tcp转串口_浅谈串口转以太网技术
  7. 信息系统项目管理师:第6章:项目进度管理(3)-章节重点汇总
  8. java 解析标记语言_Java XML可扩展标记语言(eXtensible Markup Language)
  9. 简单分布式系统构建知识
  10. Linux网站搭建(3)---内网网站发布到外网(转)
  11. 工作中线程池使用不当的问题记录(get是阻塞式的)
  12. 用Python做一个游戏辅助脚本,完整编程思路分享
  13. skywalking 安装部署以及监控远程应用
  14. tcl文件调用c语言,TCL与c/c++的互相调用
  15. JavaWeb技术之JSP
  16. 最小网元设计【阶段零】
  17. Linux环境下Nginx不支持中文文件名解决办法
  18. GitHub 标星 1000+ 的开源电子书
  19. w10计算机怎么恢复出厂设置路由器,Windows10系统重置无线wifi出厂设置的方法
  20. 杰理AC696N串口通信实验

热门文章

  1. 【Flink】Flink Kafka 消费卡死 消费组卡死 topic无写入 实际有数据 topic正常
  2. 【Elasticsearch】如何在Elasticsearch中查找相似的术语
  3. 【zookeeper】zookeeper shell 删除路径 卡死
  4. 【kafka】Kafka 2.3 空消费组延时rebalance
  5. git 提交代码到新的库,不保留原来的提交历史记录
  6. kafka : CommitFailedException Commit cannot be completed since the group has already rebalanced
  7. spark学习-29-源代码解析从start-all.sh脚本开始
  8. java自定义栈类代码,异常堆栈和自定义类
  9. 冷饭新炒:理解JDK中UUID的底层实现
  10. Oracle数据字典中查看约束信息/约束相关笔记