handle引用链:threadlocal-》looper-》messagequeue-》message-》handle-》activity
handle引用链详解:
handle持有activity(内部类持有外部类的饮用)
mag.tag持有handle对象( msg.target = this;)
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
messagequeue持有message对象
looper持有messagequeue(loop构造方法中创建messagequeue)
threadlocal作为一个map集合持有looper(looper的prepare方法中,threadlocal.set(new looper())
threadlocal是static关键字修饰的静态变量(static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
),生命周期与应用程序一样,threadlocal是一个gcRoots引用链,可达分析法gcroots引用的对象不可以被回收,由于sThreadLocal是GC Root,activity是可达的,所以activity不会被回收,就会造成内存泄漏。
在java中,可以作为GC Roots的对象主要有以下几种:
1.java栈中引用的对象
2.本地方法栈中JNI引用的对象
3.方法区中运行时常量池引用的对象
4.方法区中静态属性引用的对象
5.运行中的线程
6.由引导类加载器加载的对象
7.GC控制的对象
handle内存泄漏解决办法:
1.静态内部类+弱引用
修改Handler为static类,并使用弱引用,这样才能在静态内部类中调用外部类方法。
此种方式是打断handler->activity。因为java静态匿名内部类不会持有外部类引用。
private final WeakReference<MineActivity> mMineActivityWeak;
public MyHandler(MineActivity mineActivity){
mMineActivityWeak = new WeakReference<>(mineActivity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
MineActivity mineActivity = mMineActivityWeak.get();
if(mineActivity != null){
mineActivity.number = 5;
}
}
}
-
在activity.onDestory()方法中,将messageQueue中的消息清除掉。
此种方式是打断messageQueue->message。
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
//Handler源码中removeCallbacksAndMessages()注释含义
/**
* Remove any pending posts of callbacks and sent messages whose
* <var>obj</var> is <var>token</var>. If <var>token</var> is null,
* all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}