消息机制Handler及相关源码分析

来源:互联网 发布:sun官方java教程 pdf 编辑:程序博客网 时间:2024/05/21 09:17

一、Handler

1、工作原理:
Handler发送消息是往消息队列MessageQueue中插入一条消息,轮询器Looper会调用loop方法进行轮询,获取到消息后将该消息交给Handler处理。
2、发送消息(调用send和post的相关方法发送消息)
调用sendMessage,然后调用sendMessageDelayed,又调用了sendMessageAtTime。调用post方法,最终也是调用sendMessageAtTime方法。
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);}
会调用MessageQueue的enqueueMessage方法将消息放到消息队列中。Looper发现新消息,会处理。
3、接收消息
#Handler
public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);//是一个Runnable对象,实际是Handler的post传递的Runnable参数    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}
4、Handler实例化
通过特定的Looper来构造Handler
public Handler(Looper looper) {    this(looper, null, false);}

二、Looper:不停的从消息队列MessageQueue中查看是否有新消息。


1、创建Looper。每个线程最多只能有一个Looper对象。
(1)Looper.prepare();  
#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));}

private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);//创建一个MessageQueue.    mThread = Thread.currentThread();}
(2)Looper.prepareMainLooper:主线程创建Looper,本质也是通过prepare方法创建
2、获取Looper
(1)Looper.getMainLooper 获取主线程的Looper
(2)Looper.myLooper()获取当前线程的Looper实例
3、退出Looper
#Looper
(1)直接退出Looper
public void quit() {    mQueue.quit(false);}
(2)设置一个退出标识,将消息队列的已有消息处理完毕才能安全退出。
public void quitSafely() {    mQueue.quit(true);}
会调用MessageQueue的quit方法通知消息队列退出,MessageQueue的next方法返回null。
退出后Handler发送的消息会失败。在子线程中创建Looper,在所有消息完成后调用quit方法来终止消息循环。
4、进行轮询
Looper.looper
public static void loop() {    .....    //无限循环    for (;;) {        //调用MessageQueue的next方法取值        Message msg = queue.next();        if (msg == null) {            //木有消息了就跳出循环            return;        }        // This must be in a local variable, in case a UI event sets the logger        Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                    msg.callback + ": " + msg.what);        }        //msg.target指发送消息的Handler,交给Handler的dispatchMessage方法        msg.target.dispatchMessage(msg);        .....    }}
5、数据存取
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
通过ThreadLocal可以实现Looper在线程的数据存取。
原理:Looper作用域是线程,不用线程有不用的Looper。而ThreadLocal是一个线程内部的数据存储类。可在指定线程存储数据,其他线程无法获取。
(1)ThreadLocal使用:
ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<>();public void test() {    Log.e(TAG, "mainThread:" + mThreadLocal.get());  //主线程 结果是false    new Thread() {        @Override        public void run() {            super.run();            mThreadLocal.set(false);            Log.e(TAG, "thread1:" + mThreadLocal.get());  //线程1 结果是false        }    }.start();    new Thread() {        @Override        public void run() {            super.run();            mThreadLocal.set(true);            Log.e(TAG, "thread2:" + mThreadLocal.get());  //线程2 结果是true        }    }.start();}
(2)ThreadLocal的set方法:
public void set(T value) {    Thread currentThread = Thread.currentThread();//获取当前线程    Values values = values(currentThread);  //Value的类型是ThreadLocal.Value    if (values == null) {    //value为null,进行初始化        values = initializeValues(currentThread);    }    values.put(this, value); //调用value的put方法存值}//内部存在obect类型的数组static class Values {    private Object[] table;}
(3)ThreadLocal的get方法:
public T get() {    // Optimized for the fast path.    Thread currentThread = Thread.currentThread();    Values values = values(currentThread); //获取当前线程value对象    if (values != null) {        Object[] table = values.table;     //取出value的table数组        int index = hash & values.mask;        if (this.reference == table[index]) {            return (T) table[index + 1];   //table的下一个位置存得值就是ThreadLocal的值        }    } else {        values = initializeValues(currentThread); //初始化    }    return (T) values.getAfterMiss(this);}
set和get都是操作的当前线程的value对象的table数组。

三、MessageQueue:

内部以单链表的形式存储数据,包含两个操作,插入enqueueMessage方法和读取next方法。
next是一个无限循环的方法,如果没消息就一直堵塞。如果有新消息到来,从消息队列中取出一条数据,并将其在队列中移除。

四、主线程的消息循环

1、主线程的入口是ActivityThread的main方法
public static void main(String[] args) {    .....    //创建主线程的Looper和MessageQueue    Looper.prepareMainLooper();    ActivityThread thread = new ActivityThread();    thread.attach(false);    //获取handler    if (sMainThreadHandler == null) {        sMainThreadHandler = thread.getHandler();    }    if (false) {        Looper.myLooper().setMessageLogging(new                LogPrinter(Log.DEBUG, "ActivityThread"));    }    // End of event ActivityThreadMain.    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    //looper进行轮询    Looper.loop();    throw new RuntimeException("Main thread loop unexpectedly exited");}
返回的Handler是ActivityThread.H。包含了四大组件启动和停止的过程。
private class H extends Handler {}
主线程的消息循环模型:
(1)ActivityThread通过内部类ApplicationThread和ActivityManagerService进行进程间通信
(2)AMS会回调ApplicationThread的Binder方法
(3)ApplicationThread向H发送消息
(4)ApplicationThread将通过H将逻辑切换到ActivityThread中执行(主线程执行)

注意:
  • 一个Looper只能对应了一个MessageQueue。
  • 一个线程中只有一个Looper实例,一个MessageQueue实例,
  • 可以有多个Handler实例。

参考:Android开发艺术探索












0 0
原创粉丝点击