美文网首页
源码解析 Handler机制

源码解析 Handler机制

作者: 云木杉 | 来源:发表于2019-01-29 17:38 被阅读0次

系统为什么不允许在子线程里访问UI?那是因为Android的UI控件线程不安全,如果多线程并发访问的话会导致UI控件处于不可预期的状态。

ThreadLocal 工作原理

ThreadLocal是一个线程内部的储存类,通过它可以在指定的线程中存储数据,数据储存以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。

ThreadLocal里边维护了一个Thread的内部类ThreadLocalMap,每个Thread初始化时都会构建一个新的ThreadLocalMap,从而达到多个线程下数据的独立性,ThreadLocalMap是一个以当前ThreadLocal为key,内部类Entry为值的Map,Entry是ThreadLocalMap的内部类,里边维护了一个数组。

Handler机制 四种主体类

  • Lopper:消息轮训器
  • MessageQueue:消息队列
  • Handler:处理消息
  • Message:消息对象

开启应用时

  • 1) ActivityThread.java
    当应用启动时,会调用ActivityThread的main方法,在main方法里调用prepareMainLooper()方法和loop()方法
// ActivityThread.java
public static void main(String[] args) {
    Looper.prepareMainLooper();
    ........ 
    Looper.loop();
}
  • 2)Looper.java
    # 1 在prepare()方法里回去获取当前的Looper,如果没有的话(启动应用时是没有的)会走下面sThreadLocal.set(new Looper(quitAllowed)),在Looper的初始化操作中会初始化MessageQueue,并且绑定当前线程(当前即为ui线程);
    # 2 在loop()方法里会去获取当前Looper,并获取MessageQueue的实例,如果为null的话会有异常报出,然后遍历mQueue去拿到Message的引用msg,调用dispatchMessage(msg)(其实就是handler的dispatchMessage(msg))
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// prepareMainLooper() =>
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));
}
// Looper构造
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
// loop() 
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;
    ....
    for (;;) {
           Message msg = queue.next(); // might block
            //这里的msg.target指的就是handler
           msg.target.dispatchMessage(msg);
           msg.recycle();
    }
}


 /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

初始化Handler

  • 1)MainActivity.java
Handler mHandler = new Handler(){
      @Override
      public void handleMessage(Message msg) {
          super.handleMessage(msg);
      }
};
protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      mHandler.sendEmptyMessageAtTime(1,1000);
}
  • 2 )Handler.java
    #1 在handler初始化方法里获取looper对象,通过looper对象回去mQueue,在mHandler.sendEmptyMessage()时,通过msg.target = this将当前handler绑定到message中,再通过获取到的mQueue.enqueueMessage()将当前message传入mQueue中
public Handler() {
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
}

// => sendEmptyMessageAtTime
 public boolean sendMessageAtTime(Message msg, long uptimeMillis){
    boolean sent = false;
    MessageQueue queue = mQueue;
    if (queue != null) {
        //这里其实就是把handler赋值给message.target
         msg.target = this;
         sent = queue.enqueueMessage(msg, uptimeMillis);
     } else {
          RuntimeException e = new RuntimeException(
          this + " sendMessageAtTime() called with no mQueue");
     }
     return sent;
}

// msg.target.dispatchMessage(msg); 接上边的looper
// handleMessage(msg) 创建handler时,复用的方法
public void handleMessage(Message msg) {
}
   

总结

  • 当应用启动的时候,在ActivityThread的main方法中会调用Looper.prepareMainLooper(),执行Looper.prepare()方法,创建Looper对象,绑定与ThreadLocal的关系,在Looper对象的构造里创建MessageQueue对象

  • 应用里使用mHandler的sendMessage...方法,将当前的handler传入message中,执行mQueue.enqueueMessage(msg)方法,插入到消息队列中

  • Looper.loop()无限循环调用MessageQueue.next()方法获取message,如果获取到就传递给 Handler 的 dispatchMessage 方法,如果没有消息就堵塞住。


相关文章

网友评论

      本文标题:源码解析 Handler机制

      本文链接:https://www.haomeiwen.com/subject/trrapftx.html