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 );
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;null ;super (looper);null ;super (looper);@Override public  void  handleMessage (@NonNull  Message msg)  if  (mCallback == null ) {return ;final  Handler.Callback callback = mCallback.get();if  (callback == null ) { return ;
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);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 @Nullable @NonNull final  Runnable runnable;@NonNull final  WeakRunnable wrapper;@NonNull 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 ()  try  {if  (prev != null ) {if  (next != null ) {null ;null ;finally  {return  wrapper;public  void  insertAfter (@NonNull  ChainedRef candidate)  try  {if  (this .next != null ) {this .next.prev = candidate;this .next;this .next = candidate;this ;finally  {@Nullable public  WeakRunnable remove (Runnable obj)  try  {this .next; while  (curr != null ) {if  (curr.runnable == obj) { return  curr.remove();finally  {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 ) {
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) 0 );
WeakHandler 的实现:
1 2 3 4 5 6 7 Handler.Callback mCallback = new  Handler.Callback (){@override public  void  handleMessage (Message msg) 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;super ();new  WeakReference<>(base);super (looper);new  WeakReference<>(base);@Override public  void  handleMessage (@NonNull  Message msg)  if  (base != null ) {if  (base.mCallback != null ) {else  {
在 ExecHandler 的构造器中将 WeakHandler 用软引用包装
添加 obtainMessage() 函数 
 
1 2 3 public  final  Message obtainMessage ()  return  mExec.obtainMessage();
通过这两处优化,使得 WeakHandler 的用法与 android.os.Handler 的用法完全一致了, Handler 怎么用,WeakHandler 就怎么用,
1 2 3 4 5 6 new  WeakHandler(){@override public  void  handleMessage (Message msg) 0 );
最后附上优化后的 WeakHandler 源码