Handler Looper MessageQueue源码解析


Handler依赖于Looper,它的创建需要该线程下的Looper已经存在,而该 Looper又会有与当前的线程进行绑定,所以该Handler所处线程就是Looper创建时所在的线程。

Handler的dispatchMessage方法是在创建Handler时所用的Looper中执行的,这样就成功的将代码逻辑切换到指定的线程中去执行了。
所以,handler发送消息(send)可以在任意的线程中,但是接收消息一定是在创建Handler时所用的Looper中的线程里。


Looper
先解释一下ThreadLocal类
/**
 * Implements a thread-local storage, that is, a variable for which each thread
 * has its own value. All threads share the same { @code  ThreadLocal} object,
 * but each sees a different value when accessing it, and changes made by one
 * thread do not affect the other threads. The implementation supports
 * { @code  null} values.
 *
 *  @see  java.lang.Thread
 *  @author  Bob Lee
 */
public class ThreadLocal< T> {

set()和get()方法必须要在同一个线程中进行,否则get()中取不到值( 所以ThreadLocal.get()获得得就是当前线程对应的Looper对象
ThreadLocal 不是用于解决共享变量的问题的,不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制
ThreadLocal 是一个用来存储当前线程状态的一个成员变量,存储范围为线程内部

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


应用程序使用Lopper分为两种情况

一.主线程中使用Lopper

通过myLooper()方法可以得到当前线程的Looper对象

二.非主线程中使用Looper



Lopper对象的创建
无论是创建与主线程关联的Looper对象还是创建与子线程关联的 Looper对象,都会调用

private Looper( boolean quitAllowed) {
    mQueue new MessageQueue(quitAllowed) ;
    mThread = Thread. currentThread() ;
}

在创建Looper的同时,创建一个与之对应的MessageQueue
那么MessageQueue中的bool类型的参数quitAllowed又是干什么的呢?
我们跟进去看到最终这个参数会在MessageQueue的quit中用到
这样我们就明白了,与主线程,子线程关联的Looper对象创建过程都一样,只不过一个传入true,一个传入false
目的在主线程中创建的Looper是必须一直存在的,该Looper所对应的MessageQueue也是不可退出的。
为什么我会说主线程中创建的Looper是不允许退出的呢?可以看看Looper的quit()方法
这里直接调用了与之关联的MessageQueue中的quit方法,这样我们就明白了。


让Lopper工作起来
/**
 * 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;
        }

        // 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.dispatchMessage(msg) ;

        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() ;
    }
}


loop()方法的只要作用就是开启一个for循环,不停的去询问MessageQueue中是否有Message
我们重点看一下msg.tar.dispatchMessage(msg)这个方法
msg.tar获得的是与这个Message相对应的Handler对象,我们去看看Handler中的dispatchMessage(Message msg)方法
具体分析这个方法在Handler章节,这里只需要知道,loop中会从MessageQueue中取出Message,并交给该Message对应的Handler进行处理

总结
通过分析Looper对象的创建过程,可以得到以下结论
1.Looper可以与主线程/子线程一对一进行关联
2.Looper与MessageQueue也是一对一的关联
3.
       这就解释了,为什么在子线程中,想要创建Looper对象,必须先调用Looper.prepare()方法,而与主线程对应的Looper在进程启动时就已经创建了(后面会涉及到),所以主线程中不需要显示的创建Looper对象
      也解释了为什么子线程中想要让Looper运行起来,为什么要调用Loop.loop()方法





Handler
先从创建Handler对象说起
Handler有如下7个构造函数
Handler(),Handler(Callback),Handler(boolean)---->都会调用Handler(Callback,boolean)

Handler(Looper),Handler(Looper,Callback)----->都会调用Handler(Looper,Callback,boolean)

我们来具体分析一下这两个方法
Handler(Callback,boolean)
/**
 * Use the { @link  Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by { @link  MessageQueue#enqueueSyncBarrier(long)}.
 *
 *  @param  callback  The callback interface in which to handle messages, or null.
 *  @param  async  If true, the handler calls { @link  Message#setAsynchronous(boolean)} for
 * each { @link  Message} that is sent to it or { @link  Runnable} that is posted to it.
 *
 *  @hide
  */
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默认是该Handler所处的线程中已经创建好了Looper实例。
如上节Looper中讨论的,MainThread中的Looper在程序启动时就已经创建完毕,所以主线程中可以用这种方式直接创建
而子线程中,必须现在该线程中调用Looper.prepare()方法,然后再创建Handler,接着再调用Looper.loop()方法进行循环取消息

Handler(Looper,Callback,boolean)
/**
 * Use the provided { @link  Looper} instead of the default one and take a callback
 * interface in which to handle messages.  Also set whether the handler
 * should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by { @link  MessageQueue#enqueueSyncBarrier(long)}.
 *
 *  @param  looper  The looper, must not be null.
 *  @param  callback  The callback interface in which to handle messages, or null.
 *  @param  async  If true, the handler calls { @link  Message#setAsynchronous(boolean)} for
 * each { @link  Message} that is sent to it or { @link  Runnable} that is posted to it.
 *
 *  @hide
  */
public Handler(Looper looper Callback callback , boolean async) {
    mLooper = looper ;
    mQueue = looper.mQueue ;
    mCallback = callback ;
    mAsynchronous = async ;
}


再看一下Looper中遗留的dispatchMessage(Message msg)方法
做的事情就是将Handler发送的Message传递给该Handler来进行处理
之前分析到,dispatchMessage(Message msg)方法是在Looper.loop方法中被调用的

发送消息(本质就是将Message压入MessageQueue)
handler.post(Runnable)
handler.sendMessage(Message)
post是将一个Runnable投递到Handler内部的Looper中去处理
sendMessage是将一个消息投递到Handler内部的Looper中去处理
post最终也会调用sendMessage方法来完成

handler.post( new Runnable() {
    @Override
    public void  run() {
        textView.setText( "456") ;
    }
}) ;

通过handler.post可以直接更改UI,这里的Message就是456


MessageQueue
消息队列是由nativie的代码(JNI)创建的


Message
/**
 * Same as { @link  #obtain()}, but sets the value for the  <em> target </em>  member on the Message returned.
 *  @param  Handler to assign to the returned Message object's  <em> target </em>  member.
 *  @return  A Message object from the global pool.
 */
public static Message  obtain(Handler h) {
    Message m =  obtain() ;
    m.target = h ;

    return m ;
}

这里可以看出,每个Message只能制定一个Handler进行处理


总结
一个Thread对应一个Looper
一个Looper对应一个MessageQueue(只循环从这个MessageQueue中获得消息并调用该Message对应Handler的dispatchMessage方法)
一个MessageQueue对应多个Message
一个Message又只能指定一个Handler进行处理
所以
一个Thread可以对应多个Handler,是一对多的关系




ActivityThread
整个应用程序就是从ActivityThread的main()函数开始的
与主线程相对应的Looper对象就是在main方法中通过
Looper.prepareMainLooper()创建的
重点如下:
1.创建处理消息的环境
2.循环处理消息
也就是说,消息是推动这个系统动起来的基础,即便操作系统也是如此。



Thread






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值