目录

一、概念

二、源码分析

1、Handler机制的相关类 

2、创建Looper

3、创建MessageQueue以及Looper与当前线程的绑定

4、Looper.loop()

5、创建Handler

6、创建Message

7、Message和Handler的绑定

8、Handler发送消息

9、Handler处理消息

10、小结


一、概念

在android开发中,经常会在子线程中进行一些操作,当操作完毕后会通过handler发送一些数据给主线程,通知主线程做相应的操作。探索其背后的原理:子线程 handler 主线程其实构成了线程模型中的经典问题生产者-消费者模型。生产者-消费者模型:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加数据,消费者从存储空间中取走数据。
好处: 保证数据生产消费的顺序(通过MessageQueue,先进先出),不管是生产者(子线程)还是消费者(主线程)都只依赖缓冲区(handler),生产者消费者之间不会相互持有,使他们之间没有任何耦合。

二、源码分析

1、Handler机制的相关类 

  • Hanlder:发送和接收消息。 
  • Looper:用于轮询消息队列,一个线程只能有一个Looper。 
  • Message: 消息实体。
  • MessageQueue: 消息队列用于存储消息和管理消息。

2、创建Looper

创建Looper的方法是调用Looper.prepare() 方法,在ActivityThread中的main方法中为我们prepare了:

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    //其他代码省略... 
    Looper.prepareMainLooper(); //初始化Looper以及MessageQueue 

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Looper.loop(); //开始轮循操作 throw new RuntimeException("Main thread loop unexpectedly exited"); 
}
public static void prepareMainLooper() {
    prepare(false);//消息队列不可以quit
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

prepare有两个重载的方法,主要看 prepare(boolean quitAllowed) quitAllowed的作用是在创建MessageQueue时标识消息队列是否可以销毁, 主线程不可被销毁,下面有介绍。

public static void prepare() {
    prepare(true);//消息队列可以quit
}

// quitAllowed重要
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        //不为空表示当前线程已经创建了Looper
        throw new RuntimeException("Only one Looper may be created per thread");
        //每个线程只能创建一个Looper
    }
    sThreadLocal.set(new Looper(quitAllowed));//创建Looper并设置给sThreadLocal,这样get的 时候就不会为null了
}

3、创建MessageQueue以及Looper与当前线程的绑定

private Looper(boolean quitAllowed) { 
    mQueue = new MessageQueue(quitAllowed);//创建了MessageQueue 
    mThread = Thread.currentThread(); //当前线程的绑定 
}

MessageQueue的构造方法

MessageQueue(boolean quitAllowed) { 
    //mQuitAllowed决定队列是否可以销毁 主线程的队列不可以被销毁需要传入false, 在MessageQueue的quit()方法 就不贴源码了
    mQuitAllowed = quitAllowed; 
    mPtr = nativeInit(); 
}

4、Looper.loop()

同时是在main方法中 Looper.prepareMainLooper() 后Looper.loop(); 开始轮询

public static void loop() { 
    final Looper me = myLooper();
    //里面调用了sThreadLocal.get()获得刚才创建的Looper对象 
    if (me == null) { 
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //如果Looper为空则会抛出异常 
    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) {
            // 由于刚创建MessageQueue就开始轮询,队列里是没有消息的,等到Handler sendMessage enqueueMessage后 
            // 队列里才有消息 
            // 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);//msg.target就是绑定的Handler,详见后面Message的部 分,Handler开始
        // 后面代码省略..... 
        msg.recycleUnchecked(); 
    } 
}

5、创建Handler

最常见的创建handler

Handler handler=new Handler(){ 
    @Override 
    public void handleMessage(Message msg) {
        super.handleMessage(msg); 
    } 
};

在内部调用 this(null, false);

public Handler(Callback callback, boolean async) { 
    //前面省略 
    mLooper = Looper.myLooper();
    //获取Looper,**注意不是创建Looper**! 
    if (mLooper == null) { 
        throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); 
    }
    mQueue = mLooper.mQueue;//创建消息队列MessageQueue 
    mCallback = callback; //初始化了回调接口 
    mAsynchronous = async; 
}

Looper.myLooper();

//这是Handler中定义的ThreadLocal ThreadLocal主要解多线程并发的问题 
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 
    
public static @Nullable Looper myLooper() { 
    return sThreadLocal.get(); 
}

sThreadLocal.get() will return null unless you’ve called prepare(). 这句话告诉我们get可能返回null 除非先调用prepare()方法创建Looper。在前面已经介绍了。

6、创建Message

可以直接new Message 但是有更好的方式 Message.obtain。因为可以检查是否有可以复用的Message,用过复用避免过多的创建、销毁Message对象达到优化内存和性能的目地。

public static Message obtain(Handler h) { 
    Message m = obtain();
    //调用重载的obtain方法 
    m.target = h;//并绑定的创建Message对象的handler 
    return m; 
} 

public static Message obtain() { 
    synchronized (sPoolSync) {
        //sPoolSync是一个Object对象,用来同步保证线程安全 
        if (sPool != null) {
            //sPool是就是handler dispatchMessage 后通过recycleUnchecked 回收用以复用的Message
            Message m = sPool; 
            sPool = m.next; 
            m.next = null; 
            m.flags = 0; // clear in-use flag sPoolSize--; 
            return m; 
        } 
    }
    return new Message(); 
}

7、Message和Handler的绑定

创建Message的时候可以通过 Message.obtain(Handler h) 这个构造方法绑定。当然可以在 在Handler 中的enqueueMessage()也绑定了,所有发送Message的方法都会调用此方法入队,所以在创建Message的时候是可以不绑定的。

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

8、Handler发送消息

        Handler发送消息的重载方法很多,但是主要只有2种。 sendMessage(Message) sendMessage方法通过一系列重载方法的调用,sendMessage调用sendMessageDelayed,继续调用sendMessageAtTime,继续调用enqueueMessage,继续调用messageQueue的enqueueMessage方法,将消息保存在了消息队列中,而最终由Looper取出,交给Handler的dispatchMessage进行处理。
        我们可以看到在dispatchMessage方法中,message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的run方法,否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为null,所以会直接执行后面的handleMessage()方法。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //callback在message的构造方法中初始化或者使用 handler.post(Runnable)时候才不为空 
        handleCallback(msg); 
    } else { 
        if (mCallback != null) {
            //mCallback是一个Callback对象,通过无参的构造方法创建出来的handler, 该属性为null,此段不执行 
            if (mCallback.handleMessage(msg)) { 
                return; 
            } 
        }
        handleMessage(msg);//最终执行handleMessage方法 
    } 
}

private static void handleCallback(Message message) { 
    message.callback.run(); 
}

9、Handler处理消息

在handleMessage(Message)方法中,我们可以拿到message对象,根据不同的需求进行处理,整个Handler机制的流程就结束了。

10、小结

handler.sendMessage 发送消息到消息队列MessageQueue,然后looper调用自己的loop()函数带动MessageQueue从而轮询messageQueue里面的每个Message,当Message达到了可以执行的时间的时候开始执行,执行后就会调用message绑定的Handler来处理消息。大致的过程如下图所示:

handler机制就是一个传送带的运转机制。

  1. MessageQueue就像履带。
  2. Thread就像背后的动力,就是我们通信都是基于线程而来的。
  3. 传送带的滚动需要一个开关给电机通电,那么就相当于我们的loop函数,而这个loop里面的for循环就会带着不断的滚动,去轮询messageQueue。
  4. Message就是 我们的货物了。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐