在handler的简单用法中,我们自己简单new出一个handler 然后调用它的sendMessage方法发出一条消息。然后在handler类重写了handler的handlerMessage方法来进行处理。看似就是这么简单的俩步,其实背后隐藏了很多我们不知道的流程。
在介绍这个之前,我先介绍几个概念
1。Message 这个应该很清楚吧 就是我们发送的消息 介绍一个里面的一个方法Message.obtain函数。作用是从Message Pool中取出一个Message,如果Message Pool中已经没有Message可取则新建一个Message返回,同时用对应的参数给得到的Message对象赋值。 message Pool 我的理解就是一个缓存区。就是把用过的Message放进这里面为了以后用而已。要不每次都要new一个message起步麻烦。这个应该跟String pool的原理一样。姑且我们把它视为同一个作用的东西。
2.MessageQueue
顾名思义就是消息队列,干什么用的 当然是存放消息用的
3。Looper
我暂且叫他循环体吧。 主要就是从MessageQueue中读取消息。
4.handler 当然就是处理发来的消息了
下面我就把这个四个联系起来,看看他们在内部到底怎么执行。
首先通过handler发出一条消息,发到哪呢 肯定是MessageQueue里,最终会调用MessageQueue的 enqueueMessage函数,enqueueMessage根据上面的接收的Message的队列的构造把接收到的Message放入队列中。MessageQueue的removeMessages函数根据上面的接收的Message的队列的构造把接收到的Message从队列中删除,并且调用对应Message对象的recycle函数把不用的Message放入Message Pool中。通过Loop从MessageQueue中从前往后取出Message,然后通过Handler的dispatchMessage函数进行消息的处理(可见消息的处理是Handler负责的),消息处理完了以后通过Message对象的recycle函数放到Message Pool中,以便下次使用,通过Pool的处理提供了一定的内存管理从而加速消息对象的获取。至于如何处理就看你的handler如何定义了由你指定(三个方法,优先级从高到低:Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;Handler里面的mCallback指向的一个实现了 Callback接口的对象,里面的handleMessage进行处理;处理消息Handler对象对应的类继承并实现了其中 handleMessage函数,通过这个实现的handleMessage函数处理消息)。
大致流程就是handler------->>发送message---->>MessageQueue
Looper--->取出message从messagequeue中----->>在触发handler的消息分发函数----调用handler中定义的方法.
这里有个疑问那looper 和messagequeue什么时候生成呢。其实messagequeue在Looper创建的时候就生成了。那Looper什么时候生成呢?其实Looper是跟一个线程关联的。而主线程会自动调用prepareMainLooper生成自己的Looper,但其他线程则不会自己创建了。待会再说。
先来看看我们上次的简单handler例子。这下应该知道他们内部的流程了吧。其实我们在Hander handler=new Handler();其实就已经把主线程的Looper关联上来了,有了Looper我们也就有了MessageQueue 所以我们在调用sendMessage的时候就把这个Message发送到由Looper创建的MessageQueue里。Looper有主线程创建的,当然消息会在主线程处理了。这样就实现了简单的子线程到主线程的通信了。
那好,如果现在我要创建子线程的Looper呢 然后怎么把这个Looper绑定Handler上呢。其实很简单 在子线程调用Looper.prepare()就可以创建子线程的Looper 然后通过Looper.myLooper()就可以拿到这个Looper对象,最后就是把这个Looper 跟Handler绑定起来。其实在构建handler对象的时候我们除了我默认无参构造方法(这个就是我们上次那个例子用的)还有有参的构造方法,就是传Looper的。好了,这样就可以把Looper跟Handler绑定起来了。这你在主线程调用Handler.sendMessage就是把message发到子线程里来了。这样就实现主线程到子线程的通信了。以此类推各种样式的通信都是可以的。大家回去不妨试一下。
Android provides Handler and Looper for threads to communication with each other. For example, a child thread is launched to create an image from the web. After it is done, it notifies the main thread (or the UI thread) by sending a message using the handler that’s bound to the main thread’s message queue. The data produced by the child thread can also be included in the message. I often use this pattern if I want the main thread to update the UI with the data produced by the child thread (you probably already know why if you have been playing with threads in Android).
When a Handler is created, it’s bound to the message queue of the thread that created it. If you create it in the main thread, you don’t need any extra code to loop the message queue for the main thread since it’s already been started when you run your application. However, if you are creating a Handler in a child thread, you need to initialize the thread to listen to its message queue before creating the Handler.
class ChildThread extends Thread {
public void run() {
/*
* You have to prepare the looper before creating the handler.
*/
Looper.prepare();
/*
* Create the child handler on the child thread so it is bound to the
* child thread's message queue.
*/
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
/*
* Do some expensive operations there.
*/
}
};
/*
* Start looping the message queue of this thread.
*/
Looper.loop();
}
}