Handler 导致的 Context Leak 先看下面这段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 public  class  SampleActivity  extends  Activity   {     @Override      protected  void  onCreate (Bundle savedInstanceState)   {         super .onCreate(savedInstanceState);                  new  Handler().postDelayed(new  Runnable() {             @Override              public  void  run ()   {  }         }, 1000  * 60  * 10 );                  finish();     } }
 
Android Lint 会提示我们内存泄露风险
in Android, Handler classes should be static or leaks might occur.
 
代码中,在 Activity 的 onCreate 方法里创建了一个 Handler,然后延时执行一个消息,在这段延时时间内,如果 Activity 销毁,会导致 Activity 的泄露,原因在于 Handler 将消息提交到 MessageQueue 中,而 MessageQueue 是跟随 App 整个生命周期存在的,这个匿名 Runnable 却隐式的持有了 Activity 的引用,从而导致了内存泄露。
关于更多 Context Leak 的详细内容,可以查看这个连接 How to Leak a Context 
文中的解决方案是用 WeakReference 来包装 Activity,这种方式可以解决 Context 的泄露,但是在实际开发中,每个的 Handler 都要用 WeakReference 来包装,略显臃肿。
用 WeakHandler 替换 Handler WeakHandler 的源码 托管在 Github 上,我们来具体分析一下 WeakHandler 是如何解决 MemoryLeak 的。
WeakHandler 并没有继承自 Handler , 而是定义了一个静态内部类 ExecHandler,所有的消息发送都是由 ExecHandler 接管的,下面是 ExecHandler 的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 private  static  class  ExecHandler  extends  Handler   {     private  final  WeakReference<Handler.Callback> mCallback;     ExecHandler() {         mCallback = null ;     }     ExecHandler(WeakReference<Handler.Callback> callback) {         mCallback = callback;     }     ExecHandler(Looper looper) {         super (looper);         mCallback = null ;     }     ExecHandler(Looper looper, WeakReference<Handler.Callback> callback) {         super (looper);         mCallback = callback;     }     @Override      public  void  handleMessage (@NonNull  Message msg)   {         if  (mCallback == null ) {             return ;         }         final  Handler.Callback callback = mCallback.get();         if  (callback == null ) {              return ;         }         callback.handleMessage(msg);     } }
 
ExecHandler 用弱引用 WeakReference 包装了 Handler.Callback , 而 Handler.Callback 则是由 WeakHandler 传入的,通过它解决了 Handler.Callback 的 leak  风险 。
我们知道用 Handler 发送消息有两种方式,接下来分别来看下 WeakHandler 是如何实现的。
sendMessage(Message) 当我们用 WeakHandler 发送消息时,实际上调用了 ExecHandler 的 sendMessage(…) 方法
1 2 3 public  final  boolean  sendMessage (Message msg)   {     return  mExec.sendMessage(msg); }
 
处理消息时需要实现 Handler.Callback  接口的 handleMessage(Message) 方法,然后在 WeakHandler 构造器中传入 。
post(Runnable) 看一下 WeakHandler 的 post 方法
1 2 3 public  final  boolean  postDelayed (Runnable r, long  delay)   {     return  mExec.postDelayed(wrapRunnable(r), delay); }
 
同样是由 ExecHandler 处理的,但 Runnable 被 wrapRunnable(r) 包装了一下 
1 2 3 4 5 6 private  WeakRunnable wrapRunnable (@NonNull  Runnable r)   {     ...     final  ChainedRef hardRef = new  ChainedRef(mLock, r);     mRunnables.insertAfter(hardRef);     return  hardRef.wrapper; }
 
mRunnables 维护了一个简单的双向链表,用 ChainedRef 代表链表节点,插入到 mRunnables 的链表中,下面是 ChainedRef 的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 static  class  ChainedRef   {     @Nullable      ChainedRef next;     @Nullable      ChainedRef prev;     @NonNull      final  Runnable runnable;     @NonNull      final  WeakRunnable wrapper;     @NonNull      Lock lock;     public  ChainedRef (@NonNull  Lock lock, @NonNull  Runnable r)   {         this .runnable = r;         this .lock = lock;         this .wrapper = new  WeakRunnable(new  WeakReference<>(r), new  WeakReference<>(this ));     }     public  WeakRunnable remove ()   {         lock.lock();         try  {             if  (prev != null ) {                 prev.next = next;             }             if  (next != null ) {                 next.prev = prev;             }             prev = null ;             next = null ;         } finally  {             lock.unlock();         }         return  wrapper;     }     public  void  insertAfter (@NonNull  ChainedRef candidate)   {         lock.lock();         try  {             if  (this .next != null ) {                 this .next.prev = candidate;             }             candidate.next = this .next;             this .next = candidate;             candidate.prev = this ;         } finally  {             lock.unlock();         }     }     @Nullable      public  WeakRunnable remove (Runnable obj)   {         lock.lock();         try  {             ChainedRef curr = this .next;              while  (curr != null ) {                 if  (curr.runnable == obj) {                      return  curr.remove();                 }                 curr = curr.next;             }         } finally  {             lock.unlock();         }         return  null ;     } }
 
ChainedRef 的构造器中用 WeakReference 将 Runnable 包装在 WeakRunnable 中避免了 leak 的风险, 当我们像Handler.removeCallback() 那样移除回调时,除了移除 ExecHandler 中的 WeakRunnable ,也要把链表中的 Runnable 移除掉。
1 2 3 4 5 6 7 8 9 public  final  void  removeCallbacks (Runnable r)   {     final  WeakRunnable runnable = mRunnables.remove(r);     if  (runnable != null ) {         mExec.removeCallbacks(runnable);     } }
 
WeakHandler 的缺点 上面介绍的 WeakHandler 的实现可以看到,想要处理 handleMessage() 只能由 Handler.Callback 传入 WeakHandler 的构造器中,与 Handler 的实现相比没有那么灵活 (Handler 的构造器可以传递 Handler.Callback ,也可以按照下面的方法实现),并且 WeakHandler 中并且没有实现 obtainMessage() 
android.os.Handler 的实现:
1 2 3 4 5 6 new  Handler(){     @override      public  void  handleMessage (Message msg)  {              } }.sendEmptyMessage(0 );
 
WeakHandler 的实现:
1 2 3 4 5 6 7 Handler.Callback mCallback = new  Handler.Callback (){     @override      public  void  handleMessage (Message msg)  {              } }  WeakHandler mHandler = new  WeakHandler(mCallback);
 
优化后的 WeakHandler 
改写 ExecHandler 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private  static  class  ExecHandler  extends  Handler   {     private  final  WeakReference<WeakHandler> mBase;     ExecHandler(WeakHandler base) {         super ();         mBase = new  WeakReference<>(base);     }     ExecHandler(WeakHandler base, Looper looper) {         super (looper);         mBase = new  WeakReference<>(base);     }     @Override      public  void  handleMessage (@NonNull  Message msg)   {         WeakHandler base = mBase.get();         if  (base != null ) {             if  (base.mCallback != null ) {                 base.mCallback.handleMessage(msg);             } else  {                 base.handleMessage(msg);             }         }     } }
 
在 ExecHandler 的构造器中将 WeakHandler 用软引用包装
添加 obtainMessage() 函数 
 
1 2 3 public  final  Message obtainMessage ()   {     return  mExec.obtainMessage(); }
 
通过这两处优化,使得 WeakHandler 的用法与 android.os.Handler 的用法完全一致了, Handler 怎么用,WeakHandler 就怎么用, 同时也不用担心 MemoryLeak 啦~ :)
1 2 3 4 5 6 new  WeakHandler(){     @override      public  void  handleMessage (Message msg)  {              } }.sendEmptyMessage(0 );
 
最后附上优化后的 WeakHandler 源码