天天看点

Handler运行机制 Looper MessageQueue ThreadLocal

你只有努力奔跑,才能留在原地。

一. Handler

post or send message post 最终还是走send一样的逻辑代码:

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), );
    }

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

发送消息到messageQueue, messageQueue通过enqueueMessage method已单链表数据结构保存消息

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
           

处理Looper.loop 循环取出的消息

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {    // msg.callback 是post method 传入的回调
            handleCallback(msg);      // 该方法执行message.callback.run(); 
        } else {
            if (mCallback != null) {     //public Handler(Callback callback, boolean async) 构造Handler的时候  mCallback = callback;  
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
           

二. Looper

get message

通过loop() 方法进而MessageQueue.next()方法,循环取出MessageQueue里的Message。此处可能会死循环!

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the 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;

        // 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;
            }
            ...
    }
           
Message msg = queue.next(); 当msg == null,才退出循环;但是messageQueue.next(), 可能会一直死循环(block)!

MessageQueue.java

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == ) {
            return null;
        }

        int pendingIdleHandlerCount = -; // - only during first iteration
        int nextPollTimeoutMillis = ;
        for (;;) {
            ...
        }
    }
           

get message 之后进而给 handler 处理相应的消息

msg.target.dispatchMessage(msg);    //msg.target 就是对应的handler, handler send message 的时候这是handler send消息的时候保存在Messasg对象

           
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;    //这里传入的 handler类似接口回调
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }```    
           

三. MessageQueue

由Looper构造方法创建,当调用Looper.prepare(); 系统将会创建一个对应的MessageQueue;

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));
  }
           
private Looper(boolean quitAllowed) {
   mQueue = new MessageQueue(quitAllowed);
   mThread = Thread.currentThread();
}
           

Looper对象持有MessageQueue, Handler 通过拿到当前线程的Looper对象,进而拿到Looper的MessageQueue,再通过上面的post或者send Message到MessageQueue; Looper.loop(), 一直循环取出Message, 进而给对应的Handler处理(dispatchMessage method 处理)

四. ThreadLocal

ThreadLocal一般用来保存每个Thread特有的对象或者属性;

Looper对象就是保存在ThreadLocal里面的,通过ThreadLocal.set() save Looper对象,ThreadLocal.get() get Looper对象; 线程中只能有不超过一个Looper对象,并且Thread 跟Looper对象一对一的关系;这样用ThreadLocal来存取Looper, 就不用一个类型LooperManager类来管理所有Thread的Looper对象了。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
           

验证一下ThreadLocal.get(), ThreadLocal.set() 方法,以及ThreadLocal在多个Thread中是怎么保持自我的。

private static void testThreadLocal() {
        final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

        new Thread() {
            @Override
            public void run() {
                super.run();
                threadLocal.set();
                System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                super.run();
                threadLocal.set();
                System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
            }
        }.start();

        System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
    }
           

log:

Thread name: Thread[Thread-,,main] threadLocal value: 
Thread name: Thread[Thread-,,main] threadLocal value: 
Thread name: Thread[main,,main] threadLocal value: null
           

五. 使用中可能会遇到的问题

继续阅读