android消息机制 - Handler、Looper原理解析

android的消息机制就是指Handler、MessageQueue和Looper的工作过程。

需要传递消息时,由Handler会调用MessageQueue的enqueueMessage方法将消息放入消息队列中,Looper会不断从队列里取消息,取出以后再交给Handler去处理。

Handler在创建时要使用当前线程的Looper来构建内部的消息处理系统,所以如果当前线程没有Looper,就会报错:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

我们在主线程(ActivityThread)里使用Handler时通常都是直接使用,并没有创建Looper,那是因为系统会通过Looper.prepareMainLooper()来创建主线程的Looper,所以主线程中默认可以直接使用Handler。


Looper的工作原理

Looper的构造方法里会新建MessageQueue并保存当前的线程信息,所以MessageQueue是由Looper去创建并维护的。

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

如何去创建一个Looper?

Looper.prepare();

上述代码只是在当前线程里创建了Looper对象,要想使其工作(可以不断的从消息队列中取消息并处理消息)还需要调用:

Looper.loop();

来看一下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方法是一个死循环,不断的调用queue.next()去从消息队列中取消息。当消息为null时才会返回。需要注意的是,如果当前消息队列里没有消息,queue.next()方法会阻塞住而并不是返回null。那么什么时候才是null退出循环呢?只有调用Looper.quit()或Looper.quitSafely()方法,这样就会调用MessageQueue的quit/quitSafely来通知消息队列退出,这时queue.next()就会返回null了。

quit和quitSafely方法的区别是:quit会直接退出Looper,而quitSafely会等待当前消息队列中已有的消息全部处理完毕后才完全退出。

在子线程中,如果手动创建了Looper,那么当所有事情完成以后应该调用quit方法来终止消息循环,否则子线程会一直处于等待的状态。而当Looper退出后,Handler的send方法会返回false,线程会立刻终止,因此建议不需要的时候终止Looper。

通过queue.next()取得消息后,Looper会调用msg.target.dispatchMessage(msg); 这里的msg.target就是指Handler,这样发送的消息又交给它的dispatchMessage方法来处理了。


Handler的工作原理

我们经常使用Handler的sendMessage或sendMessageDelayed的方法,它们最终都会调到enqueueMessage()来往消息队列中插入消息。然后消息交给Looper处理,Looper又调用Handler的dispatchMessage方法。dispatchMessage的源码如下所示:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

通过源码可知,会首先检查Message的callback是否为null。Message的callback实际上就是Handler的post方法所传递的Runnable参数,这里调用的handleCallback(msg)就是要去执行Runnable的run方法:

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



其次会检查mCallback是否为null,这个Callback是指:

 /**
  * Callback interface you can use when instantiating a Handler to avoid
  * having to implement your own subclass of Handler.
  *
  * @param msg A {@link android.os.Message Message} object
  * @return True if no further handling is desired
  */
 public interface Callback {
     public boolean handleMessage(Message msg);
 }

当我们创建Handler对象时,如果是用这个构造方法,就相当于为mCallback赋值了:

public Handler(Callback callback) {
    this(callback, false);
}

我们在日常使用Handler时,经常继承它并实现handleMessage方法,实际并没有必要,只要传入Callback就可以。


Handler还有直接传入Looper的构造方法:

public Handler(Looper looper) {
    this(looper, null, false);
}

总结

通过上述原理分析,可以总结出在子线程中使用Handler的方式概括如下:

new Thread(){
    @Override
    public void run() {
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
    }
}.start();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值