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

今天偶然看看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的声明周期被触发就会毁掉这个方法。前面说到谷歌的解决方案并不能解决国内的情况,所以我们可以在这个基础上做修改,代码我也就贴出来了,需要注意的是谷歌的这种方案是针对。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值