熟悉的Handler,再看源码重新了解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wujainEW/article/details/82253876

Handler在Android中主要用于组件之间或者线程之间消息通信机制,主要有四个核心元素:Handler  Message  MessageQueue  Looper。

这里说一下简单原理:通过调用handler.sendMessage()方法将Message添加到消息队列MessageQueue,然后通过一个无限循环的Looper轮询器,不断从消息队列MessageQueue中获取消息Message,并将消息Message交给Handler的handlerMessage方法处理。需要注意的是Handler引用哪个线程的Looper就在哪个线程中处理消息,每个线程的Looper只有一个。

基本原理相信大家都了解,又重新看了Handler源码,所以弄一个总结和笔记吧O(∩_∩)O

首先从创建Handler开始看,分为两种情况,1 在主线程中创建 。2 在子线程中创建。如下:

public class MainActivity extends Activity {

 xxx...

Handler handlerA = new Handler();

new Thread(new Runnable() {

@Override

public void run() {

Handler handlerB = new Handler();

}

}).start();

xxx...

}

运行程序后,在子线程中创建Handler会导致崩溃,异常信息:Can't create handler inside thread that has not called Looper.prepare() 。说不能在没有调用Looper.prepare()方法的线程中创建Handler。根据提示修改代码:

xxx...

new Thread(new Runnable() {

@Override

public void run() {

Looper.prepare()

Handler handlerB = new Handler();

}

}).start();

xxx...

再运行一遍,ok,解决崩溃。来看看源码,得知道为什么,从Handler无参构造方法开始看:

public Handler() {

    xxx...//n行源码已经省略^_^

    mLooper = Looper.myLooper();

    if (mLooper == null) {

        throw new RuntimeException(

            "Can't create handler inside thread that has not called Looper.prepare()");

    }

    xxx...

}

从源码可以看出,通过调用Looper.myLooper( ) 方法获取了一个Looper对象,如果Looper对象为null的就抛出异常,什么时候为null,从Looper.myLooper方法开始看:

public static final Looper myLooper(){

    return (Looper)sThreadLocal.get();

}

非常简单,是从ThreadLocal中获取当前线程的Looper,ThreadLocal是一个线程内部存储的类,内部维护了一个数组,是根据当前线程的索引来获取属于当前线程的对象,线程之间不受影响,ThreadLocal不在本次分析重点^_^,就不说了。

回头看看Looper.prepare()方法,看源码:

public static final void prepare() {

    if (sThreadLocal.get() != null) {

        throw new RuntimeException("Only one Looper may be created per thread");

    }

    sThreadLocal.set(new Looper());

}

先判断ThreadLocal中是否存在Looper,没有的话,就创建一个Looper对象并添加到ThreadLocal中。这样就可以解释为什么要先调用Looper.prepare()方法才能创建Handler对象,并且也可以解释每个线程的Looper只有一个。

对,还有主线程,主线程并没有调用Looper.prepare()方法,创建Handler对象却没有崩溃,还是看源码,从ActivityThread的main方法开始看:

public static void main(String[] args) {

    xxx...

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();

    thread.attach(false);

    if (sMainThreadHandler == null) {

        sMainThreadHandler = thread.getHandler();

    }

    xxx...

    Looper.loop();

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

}

public static final void prepareMainLooper() {

    prepare();

    setMainLooper(myLooper());

    xxx...

}

在主线程中系统会通过调用Looper.prepareMainLooper()方法,方法内部又会去调用Looper.prepare()方法,所以不需要开发者自己手动调用Looper.prepare()方法了。

了解了Looper,Handler的创建过程,还需要知道Handler是如何发送一个Message对象的!怎么就可以在Handler的handleMessage()方法中获取Message消息并且加以处理。

首先要获取一个Message对象,获取方法主要三种:

1 Message msg = new Message();

2 Message msg = Message.obtain();  // 从全局池中获取Message对象

3 Message msg = handler.obtainMessage() :// 这是从一个可回收的对象池中获取Message对象。

Handler提供了多个发送消息的方法,除了sendMessageAtFrontOfQueue()方法之外,其他的最终都会调用sendMessageAtTime方法,开始看源码:

public boolean sendMessageAtTime(Message msg, long uptimeMillis){

    boolean sent = false;

    MessageQueue queue = mQueue;

    if (queue != null) {

        msg.target = this;

        sent = queue.enqueueMessage(msg, uptimeMillis);

    }

    xxx...

return sent;

}

该方法有两个参数,msg就是消息对象Message,uptimeMillis表示发送的延迟时间,如果调用的不是sendMessageDelayed()方法,uptimeMillis延迟时间就为0,代码很清晰,首先会将当前的Handler对象也就是this,赋值给msg.target。

然后通过调用MessageQueue的enqueueMessage()方法将消息添加到消息队列中。MessageQueue是一个队列,先进先出,并提供了入列和出列的方法。对于MessageQueue对象上面说过,是在创建Looper对象时候,在Looper的构造方法创建的。这里简单介绍了Message添加到MessageQueue过程,内部还有很多逻辑,就不再详细说了。

现在看Message是如何出列的,这里需要看Looper.loop()源码了:

public static final void loop() {

    Looper me = myLooper();

    MessageQueue queue = me.mQueue;

    while (true) {

        Message msg = queue.next();

            xxx...

            msg.target.dispatchMessage(msg);

            msg.recycle();

        }

    }

}

可以看出,loop()方法内部首先获取一个Looper对象,通过这个对象获取消息对列MessageQueue,然后再通过while死循环,不断的通过调用MessageQueue的next()方法来获取消息Message,如果消息队列MessageQueue中没有待处理的消息,那么next()方法就会一直处于阻塞状态,直到有新消息入列。

方法中还有一个msg.target操作,上面也说过了(将this也就是Handler对象赋值给msg.target),所以msg.target获取的就是一个Handler对象,通过调用Handler的dispatchMessage()方法,将消息发送出去。看这个方法内部实现:

public void dispatchMessage(Message msg) {

    if (msg.callback != null) {

        handleCallback(msg);

    } else {

        xxx...

        handleMessage(msg);

    }

}

哇塞,终于到这一步了O(∩_∩)O哈哈~,在方法内部会判断callback是否为null,如果为null就调用handlerCallback()方法否则就调用handleMessage()方法。事先也不知道这个callback是什么东东

猜你喜欢

转载自blog.csdn.net/wujainEW/article/details/82253876