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);
}
}
複製代碼