一、什么是Handler
Handler 、 Looper 、Message 这三者都与Android异步消息处理线程相关的概念。那么什么叫异步消息处理线程呢?
异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。
说了这一堆,那么和Handler 、 Looper 、Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。
二、handler的使用方法
1、handle.sendMessge
2、handler.post(runable)方法
handler.post()方法最终调用的还是sendMessage方法。
默认创建了一个message对象。
可以看到,在getPostMessage中,得到了一个Message对象,然后将我们创建的Runable对象作为callback属性,赋值给了此message.
注:产生一个Message对象,可以new ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。
在dispatchMessage方法中,如果message.callback,这个callback就是上面的ranable对象,然后就是调用handleCallback()方法,执行run方法。
三、handler 机制的原理
Handle的构造方法,主要是或者一个Looper对象,线程的消息循环。
通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。
随后,我们会经常调用sendMessage方法,
public final boolean sendMessage(Message msg)
{
returnsendMessageDelayed(msg,0);
}
接着是sendMessageDelayed方法。
我们有来到了sendMessageAtTime方法,然后有调用enqueueMessage()方法。
最后来了MessageQueue这个队列中,执行了quene.enqueueMessage()方法。也就是说handler发出的消息,最终会保存到消息队列中去。
最后Looper的loop的方法中,调用了handler.dispatchMessage,完成了消息发送。
ThreadLocal
实现一个线程本地的存储,也就是说,每个线程都有自己的局部变量。所有线程都共享一个ThreadLocal对象,但是每个线程在访问这些变量的时候能得到不同的值,每个线程可以更改这些变量并且不会影响其他的线程,并且支持null值。
Looper
Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建一个消息循环,调用Looper.loop()来使消息循环起作用,从消息队列里取消息,处理消息。
对于Looper主要是prepare()和loop()两个方法。
首先看prepare()方法
Looper.prepare()方法,是为当年线程设置一个Looper对象,使用ThreadLocal是保证每个线程的Looper是唯一的。其中Android主线程的Looper实在ActivityThread创建的时候就已经创建,所以,我们使用Handle的时候,并没有执行Looper.prepaer方法。
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。可以看到,将一个Looper的实例放入了ThreadLocal,判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例~相信有些哥们一定遇到这个错误。
在Looper的构造方法中创建一个MessageQueue实例。
在Looper的loop方法 有一个阻塞时的消息循环,只有要消息传入,就会调用Handler.dispatchMessage();
其中 MessageQueue的核心方法,next()方法就是从MessageQueue队列中获取信息。从源码分析中可以看出
从上面的源码中我们知道:队列被激活之后,首先判断队首是不是消息屏障,如果是则跳过所有的同步消息,查找最先要处理的异步消息。如果第一个待处理的消息还没有到要处理的时机则设置激活等待时间;否则这个消息就是需要处理的消息,将该消息设置为inuse,并将队列设置为非 blocked状态,然后返回该消息。next()方法是一个无线循环的方法,如果消息队列中没有消息,那么next()方法会一直阻塞,当有新消息到来时,next会将这条消息返回同时也将这条消息从链表中删除。
Looper主要作用:
1、与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是乎:Handler登场了。
四、handler 引起的内存泄漏以及解决方法
参考文献
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系