Android_Handler源码分析

Android_Handler源码分析


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/72826128


  • handler可以让耗时操作在辅助线程进行,处理完发送消息,让ui更新在主线程进行
  • 关键词: handler [ˈhændlɚ] / message [ˈmɛsɪdʒ] / runnable [‘rʌnəbəl] / looper [‘lu:pə] / message queue [kju] (注:很多程序员Queue的发音不标准)

项目使用(用于实际开发中的代码)

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private static final int MESSAGE = 0x0001;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
             switch (msg.what){
                case MESSAGE:
                    Log.e(TAG, "what:" + msg.what); // what:1
                    Log.e(TAG, "obj:" + msg.obj); // obj:sendEmptyMessage(what)
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    public void sendMessage(View v) {
        new Thread() {
            @Override
            public void run() {
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = "sendEmptyMessage(what)";
                // 多种handler发送方式
                // handler.sendEmptyMessage(1);
                handler.sendMessage(msg);
                // handler.postDelayed(new Runnable() {
                //   @Override
                //   public void run() { }
                // }, 5 * 1000);
                super.run();
            }
        }.start();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        handler.removeCallbacksAndMessages(null);
        handler = null;
        super.onDestroy();
    }
}

基本使用(用于讲解)

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
    }
};
  • handler在主线程创建
public void sendMessage(View v) {
    new Thread() {
        @Override
        public void run() {
            Message msg = Message.obtain();
            msg.what = 1;
            msg.obj = "sendEmptyMessage(what)";
            handler.sendMessage(msg);
            super.run();
        }
    }.start();
}
  • 子线程处理完耗时操作,通过handler发送Message / Runnable, 通知更新handler更新ui
  • handler.post(runnable) 底层源码调用与handler.sendMessage(message)相同,都是调用handler.sendMessageAtTime(message)

源码分析

1.先看下new Handler()的源码

public class Handler {
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        // ↓↓↓
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // ↓↓↓
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
}
  • Handler会调用 Looper.myLooper() 去获取Looper

    public final class Looper {
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    }
    • Looper是调用 sThreadLocal.get() 获取的
  • 如果 sThreadLocal.get() 没有获取到对应的该线程的Looper, 则会抛 RuntimeException; 如果有获取到对应的Looper, 则执行 mQueue = mLooper.mQueue 获取 MessageQueue
  • 那么什么时候是有Looper, 什么时候又是没有的呢?

    • 在主线程创建 Handler 不会抛该异常 (基本使用的案例代码,handler就是在主线程创建的)
    • 在子线程创建的 Handler 就抛了该异常

      new Thread(new Runnable() {
          @Override
          public void run() {
              Looper.prepare(); // <=
              handler = new Handler() {
                  @Override
                  public void handleMessage(Message msg) {
                  }
              };
              Looper.loop(); // <=
          }
      }).start();
      • 当我们在子线程中创建 Handler 之前调用 Looper.prepare() 就不会抛该异常了
      • 我们猜想可能是调用 Looper.prepare() 给 ThreadLocal 设置Looper

        public final class Looper {
            public static void prepare() {
                prepare(true);
            }
            private static void prepare(boolean quitAllowed) {
                if (sThreadLocal.get() != null) {
                    throw new RuntimeException("Only one Looper may be created per thread");
                }
                // ↓↓↓
                sThreadLocal.set(new Looper(quitAllowed));
            }
        }
        • 正符合我们的猜想, 给 ThreadLocal 设置了一个新的 Looper()
        • 我们在看看 new Looper(quitAllowed) 时做了什么

          public final class Looper {
              private Looper(boolean quitAllowed) {
                  mQueue = new MessageQueue(quitAllowed);
                  mThread = Thread.currentThread();
              }
          }
          • 可以看出 MessageQueue 是由 Looper创建的
      • 我们再调用 Looper.loop(), Handler才能收到消息, 我们来看看他到底做了什么?

        public final class Looper {
            public static void loop() {
                // ↓↓↓
                final Looper me = myLooper();
                if (me == null) {
                    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
                }
                // ↓↓↓
                final MessageQueue queue = me.mQueue;
        
                // Make sure the identity of this thread is that of the local process,
                // and keep track of what that identity token actually is.
                Binder.clearCallingIdentity();
                final long ident = Binder.clearCallingIdentity();
        
                // ↓↓↓
                for (;;) {
                    // ↓↓↓
                    Message msg = queue.next(); // might block
                    if (msg == null) {
                        // No message indicates that the message queue is quitting.
                        return;
                    }
        
                    // This must be in a local variable, in case a UI event sets the logger
                    final Printer logging = me.mLogging;
                    if (logging != null) {
                        logging.println(">>>>> Dispatching to " + msg.target + " " +
                                msg.callback + ": " + msg.what);
                    }
        
                    final long traceTag = me.mTraceTag;
                    if (traceTag != 0) {
                        Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                    }
                    try {
                        // ↓↓↓
                        msg.target.dispatchMessage(msg);
                    } finally {
                        if (traceTag != 0) {
                            Trace.traceEnd(traceTag);
                        }
                    }
        
                    if (logging != null) {
                        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    }
        
                    // Make sure that during the course of dispatching the
                    // identity of the thread wasn't corrupted.
                    final long newIdent = Binder.clearCallingIdentity();
                    if (ident != newIdent) {
                        Log.wtf(TAG, "Thread identity changed from 0x"
                                + Long.toHexString(ident) + " to 0x"
                                + Long.toHexString(newIdent) + " while dispatching to "
                                + msg.target.getClass().getName() + " "
                                + msg.callback + " what=" + msg.what);
                    }
        
                    msg.recycleUnchecked();
                }
            }
        }
        • 调用 Looper me = myLooper() 获取Looper
        • 调用 MessageQueue queue = me.mQueue 获取MessageQueue
        • 可以看出 MessageQueue是在Looper对象中的, 这可以说明一个每个 Looper 都包含一个 MessageQueue
        • for (;;) 可以看出Looper做了永生循环
        • 调用 Message msg = queue.next(), 从 MessageQueue 中取出Message
        • 调用了 msg.target.dispatchMessage(msg), 那么 msg.target 是什么呢? 先留着
        • 最后调用了 msg.recycleUnchecked()

          public final class Message implements Parcelable {
              void recycleUnchecked() {
                  // Mark the message as in use while it remains in the recycled object pool.
                  // Clear out all other details.
                  flags = FLAG_IN_USE;
                  what = 0;
                  arg1 = 0;
                  arg2 = 0;
                  obj = null;
                  replyTo = null;
                  sendingUid = -1;
                  when = 0;
                  target = null;
                  callback = null;
                  data = null;
          
                  synchronized (sPoolSync) {
                      if (sPoolSize < MAX_POOL_SIZE) {
                          next = sPool;
                          sPool = this;
                          sPoolSize++;
                      }
                  }
              }
          }
          • 可以看出 msg.recycleUnchecked() 只是对 Message 做了初始化,并返回了池子里

2.在看下 Message msg = Message.obtain(); 的源码

public final class Message implements Parcelable {
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
}
  • 很简单, 就是从池子里去取 Message, 如果池子里没有就 new Message()

3.再来看看 handler.sendMessage(msg) 的源码

public class Handler {
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        // ↓↓↓
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // ↓↓↓
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}
  • 现在 msg.target 是什么的问题解决了,原来他是 Handler, msg.target.dispatchMessage(msg) 是什么意思?待会儿继续看源码, 现在暂时先跳过
  • 最后调用了 queue.enqueueMessage(msg, uptimeMillis)

    public final class MessageQueue {
        boolean enqueueMessage(Message msg, long when) {
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
    
            synchronized (this) {
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    Log.w(TAG, e.getMessage(), e);
                    msg.recycle();
                    return false;
                }
    
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                if (p == null || when == 0 || when < p.when) {
                    // New head, wake up the event queue if blocked.
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    // Inserted within the middle of the queue.  Usually we don't have to wake
                    // up the event queue unless there is a barrier at the head of the queue
                    // and the message is the earliest asynchronous message in the queue.
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
    
                // We can assume mPtr != 0 because mQuitting is false.
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    }
    • 看起来很复杂, 其实主要是将 Message 根据 when时间值 插入到队列中

4.最后看看一个遗留的问题, msg.target.dispatchMessage(msg) 是什么意思? 通过3的分析我们已经知道 msg.target 是Handler对象

public class Handler {
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

    public void handleMessage(Message msg) {
    }
}
  • 原来是回调 handleMessage 的意思啊

5.简单的总结下,顺便画个图捋一捋

  • 创建Handler前,(先调用 Looper.prepare() [prɪˈper], 创建Looper(同时Looper会创建MessageQueue)), 再创建 Handler, (然后调用 Looper.loop(), 让Looper的永生循环执行起来)
  • Handler 通过 handler.sendMessage(msg), 将自己放入 Message 中,然后将 Message 放入 Looper 的 MessageQueue 队列中
  • Looper 不断的从 MessageQueue 中取出 Message, Message 里的 Handler 调用回调方法.

handler引发的内存泄露问题

Q. (基本使用的代码)使用内部类创建 Handler, 该Handler隐式持有Activity的引用,可以调用Activity的属性和方法;如果Handler发送的延迟Message等待时间过长,而此时Activity正在被回收时, 由于Message持有Handler的引用,而Handler持有Activity的引用,导致该Activity无法被回收,从而导致内存泄露问题.

A. 解决方案:(完整代码见项目使用)

  • Activity销毁时,清空该Handler相关的所有Message, 并将Handler指向null.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值