本篇簡單的講一下日常使用Handler時形成內存泄漏的問題。面試
什麼是內存泄漏?大白話講就是分配出去的內存,回收不回來。嚴重會致使內存不足OOM。下面來看一下形成內存泄漏的代碼:ide
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或其餘邏輯???或者咱們知道內部類持有外部類引用也行。那麼怎麼解決那?oop
解決辦法:將內部類改成靜態內部類,由於靜態內部類不持有外部類引用。因爲Handler再也不持有外部類引用,致使程序不容許你在Handler中操做Activity中的對象了。因此你還須要在Handler中增長一個對Activity的弱引用(使用弱引用的好處在於:activity一旦被置爲null,他就會被馬上回收)。上面持有的引用屬於強引用,強引用的特色就是噹噹前類被回收的時候,若是它被強引用所持有,那麼當前類是不會被回收的!!!因此咱們改爲軟引用持有當前類對象,這樣在GC回收時會忽略掉弱引用,即就算有弱引用指向某對象,該對象也會在被GC檢查到時回收掉。ui
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的時候繼承這個基類就好。this
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對象時,都不會形成內存泄漏了。spa
至此,Handelr系列講解到此結束,大多數都是參數慕課網的《Android面試常客Handler詳解》,我這裏只是將視頻中的內容加上本身的理解紀錄下來,但願對你們有所幫助。線程