Handler机制(Looper、Message、MessageQueue)源码追踪

介绍

本文是自己看Handler源码的一个流程,主要对主线进行了追踪查看。
如有写的不正确或者分析不正确的,麻烦大佬指出。跪谢啦!

Handler机制涉及主要相关类

  • Handler
发消息、处理消息
  • Looper
轮询消息队列,一个线程只有一个Looper
  • Message
消息的存储对像
  • MessageQueue
消息列表(消息不会直接添加到MessageQueue中,
而是通过与Looper关联的{@link Handler}对象)

先抛出几个问题:

  1. Looper什么时候创建的?
  2. MessageQueue什么时候创建的?
  3. Looper和当前线程是什么时候绑定的?
  4. Message和Handler什么时候绑定的?
  5. Message什么时候放入MessageQueue?

源码追踪

new Handler();

先从new 一个Handler看起:

点进去,看到Handler构造方法里调用了

mLooper = Looper.myLooper();

    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();// 这里获取一个Looper
        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;
    }

关键方法: Looper.myLooper()

myLooper();点进去发现是sThreadLocal.get()直接获取的。

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

而sThreadLocal是一个用来存储Looper的本地变量

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

我们再去查看sThreadLocal 哪里调用了。
Handler机制(Looper、Message、MessageQueue)源码追踪发现只有三个地方调用了,有一个调用的方法是直接设置Looper的:

sThreadLocal.set(new Looper(quitAllowed)); 发现这里直接是new Looper。

关键方法:sThreadLocal.set(new Looper(quitAllowed));

继续追踪,发现sThreadLocal.set(new Looper(quitAllowed)); 是在prepare方法里调用的。

 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的创建时间!

好奇宝宝肯定点击进去看下的:new Looper();我们点击看下


    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
        // 是不是发现了什么,MessageQueue在Looper的构造方法里创建的,同时Looper和线程也绑定了

总结: Looper的创建时间,也是MessageQueue创建的时间,同时 也是Looper和线程绑定的时间。

关键方法:prepare

继续追踪,谁又调用了prepare

prepare();

    public static void prepare() {     //   消息队列可以quit
        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));
    }

继续追踪,发现 Looper.class 的107行调用的prepare(false);

    public static void prepareMainLooper() {
        prepare(false);         // 这里调用的prepare。//消息队列不可以quit
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

再继续追踪prepareMainLooper ,我们会追踪到ActivityThread这个类里面。

prepareMainLooper()

主线程就是UI线程,Activity由ActivityThread启动,会调用ActivityThread的main函数:


    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

		// 省略N行代码................
        Looper.prepareMainLooper(); //  看到这里我们就明白了,

        ActivityThread thread = new ActivityThread();
        thread.attach(false);
		// 省略N行代码................
        Looper.loop();// 开始轮询

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

我们从使用Handler处追踪,到这里我们是往上层追踪到ActivityThread的**main(String[]args)**方法里。

这就证明了Looper的创建时间,Activity启动时就会为ui线程创建一个Looper。Looper构造方法里进行MessageQueue的创建、Looper和线程的绑定。**

关键方法流程:

new Handler()  ---->  
Looper.myLooper() ----> 
sThreadLocal.set(new Looper(quitAllowed)) ---->
prepare(boolean quitAllowed)  ---->
prepareMainLooper()---->
ActivityThread的main(String[] args)

附上流程图:
Handler机制(Looper、Message、MessageQueue)源码追踪

Message的创建、以及与Handler的绑定

消息创建

Message obtain = Message.obtain();也可以直接new Message ();使用obtain很更好点,看下方源码上的注释:

//obtain 源码中有很多这个方法,这里只拷贝出这两个
/**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     * 从全局池返回一个新的消息实例。让我们
      *在很多情况下避免分配新对象
     */
 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();
    }
    //这里也可以直接绑定Handler,即使不绑定Handler中enqueueMessage也会去绑定的 
public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }

Message与Handler的绑定、Message放入MessageQueue

handler发送消息的几个方法:

  • sendEmptyMessage()
  • sendEmptyMessageAtTime()
  • sendEmptyMessageDelayed()
  • sendMessageAtFrontOfQueue();
  • sendMessage()
  • sendMessageAtTime()
  • sendMessageDelayed

我们换个方向从这里作为入口去追踪 Message与Handler的绑定:
点击去一直往下追踪,会发现调用哪个最终都会调用enqueueMessage();(post(); (post开头的几个函数也是一样)):

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;    // 这里是Handler与Message的绑定
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);  //最终消息都会放入MessageQueue 
    }

Handler处理消息

  Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //我们从handleMessage点击去继续追踪
        }
    };

消息最终由Looper取出,交给Handler的dispatchMessage进行处理

 /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * 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);
        }
    }

还记得 会调用ActivityThread的main函数吗?调用了 Looper.loop();

  public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

		// 省略N行代码................
        Looper.prepareMainLooper(); //  看到这里我们就明白了,

        ActivityThread thread = new ActivityThread();
        thread.attach(false);
		// 省略N行代码................
        Looper.loop();// 开始轮询

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Looper.loop();
最终由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;
         /// 省略N行代码...........
        for (;;) {
            Message msg = queue.next(); // might block
           /// 省略N行代码...........
            try {
                msg.target.dispatchMessage(msg);  // 这里调用了Handler的dispatchMessage进行消息分发
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           /// 省略N行代码...........
        }
    }

附上消息分发流程图:
Handler机制(Looper、Message、MessageQueue)源码追踪

补充

handler发消息给子线程(子线程可不可以new Handler()),looper怎么启动?

场景:Handler的创建不是在主线程创建的,是在子线程创建的

public class MainActivity extends AppCompatActivity {
    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new MyRunnable()).start();

        findViewById(R.id.send_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = SEND_MESSAGE;
                msg.obj = "主线程向子线程发送新的消息啦";
                mHandler.sendMessage(msg);
            }
        });
    }

    private class MyRunnable implements Runnable {
        @Override
        public void run() {
            //建立消息循环的步骤
            Looper.prepare();//1、初始化Looper
            mHandler = new Handler() {// 2、绑定handler到CustomThread实例的Looper对象
                public void handleMessage(Message msg) {
                   //4.处理消息
                }
            };
            Looper.loop();//3、启动消息循环
        }
    }
     }
  1. 首先通过 Looper.prepare() 初始化Looper
  2. new Handler();创建Handler就是绑定当前Thread实例的Looper对像
  3. Looper.loop(); 启动消息循环
  4. 最后handleMessage就可以正常接收消息了

注:在子线程new Handler();需要先去初始化Looper,还要去开启Looper.loop()。如上所示

注:如有什么不对,理解不到位的麻烦各位看官指出!在下感激不尽。