本篇簡單的講一下平常使用Handler時造成內存泄漏的問題。
什么是內存泄漏?大白話講就是分配出去的內存,回收不回來。嚴重會導致內存不足OOM。下面來看一下造成內存泄漏的代碼:
public class MemoryLeakActivity extends Activity { private MyHandler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); mHandler = new MyHandler(); mHandler.sendEmptyMessage(1); } private class MyHandler extends Handler{ public MyHandler(){ } @Override public void handleMessage(Message msg) { super.handleMessage(msg); } } }
上面的代碼我們不用管發送消息、接受消息,因為之前已經詳細講過了,不是本篇的重點。本篇我想說上面的代碼會造成內存泄漏,什么意思?Handler持有MemoryLeakActivity引用,為什么?如果不持有當前類的引用,我怎么更改當前類的ui或其他邏輯???或者我們知道內部類持有外部類引用也行。那么怎么解決那?
解決辦法:將內部類改為靜態內部類,因為靜態內部類不持有外部類引用。由於Handler不再持有外部類引用,導致程序不允許你在Handler中操作Activity中的對象了。所以你還需要在Handler中增加一個對Activity的弱引用(使用弱引用的好處在於:activity一旦被置為null,他就會被立刻回收)。上面持有的引用屬於強引用,強引用的特點就是當當前類被回收的時候,如果它被強引用所持有,那么當前類是不會被回收的!!!所以我們改成軟引用持有當前類對象,這樣在GC回收時會忽略掉弱引用,即就算有弱引用指向某對象,該對象也會在被GC檢查到時回收掉。
public class MemoryLeakActivity extends Activity { private MyHandler myHandler; private static final int ACTION_GOTO_MAIN = 1001; private static final int GOTO_MAIN_TIMER = 2 * 1000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); myHandler = new MyHandler(this); } @Override protected void onResume() { super.onResume(); if (myHandler != null) { myHandler.sendEmptyMessageDelayed(ACTION_GOTO_MAIN, GOTO_MAIN_TIMER); } } @Override protected void onPause() { super.onPause(); if (myHandler != null && myHandler.hasMessages(ACTION_GOTO_MAIN)) { myHandler.removeMessages(ACTION_GOTO_MAIN); } } protected static class MyHandler extends Handler { private WeakReference<MemoryLeakActivity> mActivity; public MyHandler(MemoryLeakActivity activity) { mActivity = new WeakReference<MemoryLeakActivity>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MemoryLeakActivity activity = mActivity.get(); if (activity == null) return; if (msg.what == ACTION_GOTO_MAIN) { //處理邏輯 } } } }
上面代碼很好的解決了內存泄漏的問題。但是這段代碼可能會在很多界面都會遇到,難道每個界面都需要這樣寫嗎?重復的工作啊,所以干脆我們抽取成一個基類,將來創建Handler的時候繼承這個基類就好。
public abstract class WeakHandler<T> extends Handler { protected WeakReference<T> reference; //創建子線程Handler使用的構造器 public WeakHandler(Looper looper, T reference) { super(looper); this.reference = new WeakReference<>(reference); } //創建主線程Handler使用的構造器 public WeakHandler(T reference) { this.reference = new WeakReference<>(reference); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); T t = reference.get(); if (t == null) return; handleMessage(t, msg); } protected abstract void handleMessage(T t, Message message); }
上述代碼,我們使用了泛型,這個泛型就是我們之前說的當前類,同時提供了兩種構造器,這樣不管我們是創建主線程還是非主線程Handler對象時,都不會造成內存泄漏了。
至此,Handelr系列講解到此結束,大多數都是參數慕課網的《Android面試常客Handler詳解》,我這里只是將視頻中的內容加上自己的理解紀錄下來,希望對大家有所幫助。