1、Handler不仅能将子线程的数据传递给主线程,还可以在任意两个线程中实现数据传输。
2、通常我们在主线程中创建Handler;然后重写该Handler的handlerMessage方法。
其中Message的几个属性:
Message.what-----标识信息的int值,判断信息来自哪里。
Message.arg1/Message.arg2------初始定义传递int类型的变量
Message.obj-------用来传递任何实例化对象。
最后通过sendMessage将Message发送出去。
3、在两个子线程中通过handler发送数据。其中一个子线程初始化Handler。实现handlerMessage方法,另一个子线程通过sendMessage发送数据。需要注意的是,在初始化Handler时需要在开始创建Looper。方法为Looper.prepare()。最后还需要Looper.loop()。
如果不进行prepare()方法将报异常;不进行loop()方法将不能接收到消息。
在prepare()方法中在当前thread创建一个Looper()。ThreadLocal主要是用于维护线程的本地变量。Looper的构造函数中又创建了MessageQueue()对象。
在主线程中创建Handler不需要重新调用Looper.prepare()和Looper.loop()。是因为APP初始化都会执行ActivityThread的main方法。在这个方法中调用了Loop.prepareMainLooper()和Looper.loop()方法。
4、Handler发送消息。调用Handler不同参数发送Message最终都会调用sendMessageAtTime方法。关键方法在于enqueueMessage()方法内部调用了messageQueue的enqueueMessage()方法。
5、Message被存入MessageQueue时是将Message存到了上一个Message.next上,形成一个链式的列表,同时保证Message列表的时序性。
6、Looper.loop()方法。在调用Looper.prepare()方法之前不能调用该方法,否则抛出异常。myLooper()方法取出了当前线程的looper对象,然后从looper对象开启了一个死循环不断从looper内的MessageQueue中取出Message。只要有Message对象,就会通过Message的target调用dispatchMessage去分发消息。其中target就是我们创建的handler。
7、dispatchMessage方法。如果我们设置了callback(Runnable对象),则会直接调用handleCallback方法。比如我们经常写的runOnUiThread方法,直接调用run方法。如果msg.callback为空的话,就会调用handler的handlerMessage方法。
8、handler所创建的线程需要维护一个唯一的Looper对象,每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证。Looper对象内部又维护唯一一个MessageQueue。所以一个线程可以有多个handler,但只能有一个Looper和一个MessageQueue。
9、handler使用过程中内存泄漏问题。
为什么会出现内存泄漏:Handler使用时用来进行线程间通信的,新开启的线程会持有Handler引用,如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。
(1)首先,非静态内部类是会隐式持有外部类的引用,所以当其他线程持有了该Handler,线程没有被销毁,则意味着Activity会一直被Handler持有引用而无法导致回收。
(2)同时,MessageQueue中如果存在未处理完的Message,Message的target也是对Activity等的持有引用,也会造成内存泄漏。
解决方法:(1)使用静态内部类+弱引用的方式。静态内部类不会持有外部类的引用,当需要引用外部类操作时通过弱引用获取到外部类相关操作,弱引用不会造成对象回收不掉的问题。
(2)在外部类对象被销毁时,将MessageQueue消息清空,handler.removeCallbacksAndMessages(null)。
10、在使用Handler时通常使用Handler.obtainMessage()来获取Message对象,内部调用的是Message.obtain()方法,而不是直接new一个Message。
查看obtain()方法。在Message中有一个static Message变量sPool,这个变量用于缓存Message对象。不为空,返回当前的sPool。指向之前sPool的next对象。如果sPool为空,则需要创建一个新的Message(new Message)。
使用obtain获取Message对象是因为Message内部维护了一个数据缓存池,回收的Message不会立马销毁,而是放入缓存池,会优先从缓存池中获取Message,为null才会创建新的Message。每次使用完后会调用recycle回收。
11、linux层去实现阻塞式循环,有消息就去执行,没消息就休眠。queue.next()的源码里有个nativePollOnce()进入了JNI C代码里,有立即执行的message就会立即返回,没有的话nativePollOnce()无法返回,线程就会进入休眠。