ps:看本文以前最好先了解一下Handler源码java
咱们通常使用Handler使用匿名内部类的写法,也就是:android
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(MainActivity.HANDLER_MAIN_CODE);
}
});
复制代码
这时咱们就会发现,匿名内部类的地方会报黄: *这里提示的大意是:这个Handler类应该被设置为静态不然可能发生内存泄漏。*wtf???为何会发生内存泄漏。内存泄漏究竟是一个什么东西。web
这个嘛,详细内容你们能够阅读《深刻理解Java虚拟机》,前段时间刚出第三版,是紫色的,相比第二版加了不少内容。 简单来讲就是,当堆中分配的一块内存区域使用完毕,以后不会在被使用到,应该要被回收时,若是还存在一个强引用引用着这块内存区域,那么这块区域就没法被回收。此时就会发生内存泄漏。markdown
那为何说使用匿名内部类来使用Handler 在handler.sengMessage时,Message拥有了Handler的引用,而内部类Handler隐式的拥有外部类(Activity)的引用。一个线程中有一个Looper,Looper中有惟一一个MessageQueue,而Message在MessageQueue中,也就是产生了下面这条引用链: app
若是此时,若是调用Activity.finish();将Activity销毁:当GC线程开始工做时,会从GC Roots开始检索引用链,就会发现Activity会被上图中的一条引用链所链接,若是Message此时还在消息队列中(试着发送一条延迟5min的消息,那么消息会一直在队列中直到5min后这条消息被取出交给Handler处理,在这5min以内Activity被finish掉,可是Activity指向的内存区域是没法回收的,也就是发生了内存泄漏),则这条引用链会一直引用着Activity,使Activity的这块堆内存空间没法回收,致使内存泄漏。因此,解决方法就要从源头解决,断开引用链:ide
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
复制代码
下面是基于这种方法封装的一个SafeHandler,你们若是能理解下面这个封装的SafeHandler类,那么Android 的Handler内存泄漏知识点就完全掌握了!:oop
package com.wiz.car.common.util;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import java.lang.ref.WeakReference;
/** * 弱引用封装Handler * @param <T> */
public abstract class SafeHandler<T> extends Handler {
private final WeakReference<Context> mReference;
private final WeakReference<T> mReferenceT;
public SafeHandler(Context context, T t) {
mReference = new WeakReference<>(context);
mReferenceT = new WeakReference<>(t);
}
/** * 执行体 * @param t */
public abstract void execute(T t);
private Runnable innerRun = new Runnable() {
@Override
public void run() {
Context context = mReference.get();
if(context != null) {
if(context instanceof Activity && ((Activity)context).isFinishing()){
release();
LogUtils.w("SafeHandler :","The task executed, but "+context.getClass().getSimpleName()+" is finishing!");
}else {
T t = mReferenceT.get();
if(t != null) {
execute(t);
LogUtils.w("SafeHandler :","The task executed in "+context.getClass().getName());
}else{
LogUtils.w("SafeHandler :","The task executed, but callback class is null");
}
}
}else {
release();
LogUtils.w("SafeHandler :","The task executed, but activity destroyed!");
}
}
};
/** * 暂停任务 */
public void stop() {
removeCallbacks(innerRun);
}
/** * 销毁任务 */
public void release(){
stop();
mReference.clear();
mReferenceT.clear();
}
/** * 延迟执行 * @param time 延迟时间 */
public void postDelayed(long time) {
stop();
postDelayed(innerRun, time);
}
}
复制代码