Handler定义以及作用
handler
是andorid
的一套消息传递机制,用于跨线程通信,主要用于工作线程与主线程间的交互。andorid
的UI
操作需要在主线程上操作,一般耗时都放到其它的子线程下操作。耗时操作返回的结果在UI
线程先的展示需要跨线程通信 这个时候就可以使用handler
来通信了
Handler使用流程图
Handler原理图
几个关键的类:
- Message:数据单元,
MessageQueue
的一个个数据。 - Looper:
MessageQueue
跟Handler
的通信中间人。两个作用:不断循环从MessageQueue
中取出Message
,将Message
发送给对应的Handler
。 - MessageQueue:数据结构(先进先出)存储
Message
- Handler:线程间通行的中间人,
Message
信息的逻辑处理者,将Message
发送到MessageQueue
,处理Looper
发送过来的Message
基础使用
关键代码1: 先定义MyHanlder
继承Handler
关键代码2:新建myHandler
对象,将MainActivity
传入MyHandler
,MyHandler
弱引用MainActivity
,所以MyHandler # handleMessage()
处理需要if (null != mActivity.get())
做一下对象null判断 关键代码3:构建Message
,可以从缓存池中获取,也可以直接自己new Message
,并发送myHander.sendMessageDelayed(message,5000)
其实平时的写法有些同学是在
MainActivity
中直接定义匿名内部类MyHander
那种做法会调来内存泄漏的风险。因为匿名内部类引用着外部类,导致外部类被挟持,这就有可能导致内存泄漏了。 上面这种用法可以避免handler
挟持了外部类MainActivity
的引用
handler发送数据的两种不同的形式
sendxxx()
的方法 看一下源码几种方法的区别:
从上面可以看到,方法的最后都是调用到了sendMessageAtTime(Message msg, long uptimeMillis)
,看了一下上面的方法大家都懂各个方法的区别了。 主要是要注意一下使用的时候sendMessageAtTime(Message msg, long uptimeMillis)
跟sendMessageDelayed(Message msg, long delayMillis)
的区别,一个是当前的时刻,一个 当前的时刻+delayMillis
2.postxxx()
的方法
看一下源码几种方法的区别:
对应使用了sendxxx
的方法,主要看一下getPostMessage()
这个方法
这里有个坑 要记得看一下:
Handler.post(Runnable)
其实就是生成一个what = 0
的Message
如果你先调用Handler.post(Runnable)
再调用发送任何一条what = 0
的Message
会导致原来的被remove
掉,从而看到一脸懵逼 具体的等下代码解析再看一下
源码解析
从主线程开始入手吧~ ####ActivityThread
关键代码1:先调用Looper.prepareMainLooper()
关键代码2:获取sMainThreadHandler
,获取ActivityThread
的mH
对象,mH
对象实现了handleMessage(Message msg)
方法 关键代码3:Looper.loop()
开启循环
我们先看一下关键代码1 看一下Looper
这个类以及对象的调用方法()
Looper(部分源码)
Looper.prepareMainLooper()
:这个方法的相关调用流prepare(false)
->sThreadLocal.set(new Looper(quitAllowed));
->myLooper()
->sThreadLocal.get()
这里产生了一个looper
并设置到sThreadLocal
中,获取的时候也是从sThreadLocal
中去获取。而且在prepare(false)
中做判断,如果已经存在就不能再调用该方法,也就是说 一个线程中只能存在一个Looper
,且一个Looper
只能拥有一个mQueue
,则说明Looper
跟MessageQueue
是一对一关系Looper.loop()
:这个方法的相关调用流程me
->me.mQueue
->(for (;;)-> queue.next()->msg.target.dispatchMessage(msg)
) 开启死循环不断的轮训MessageQueue
,msg.target
其实返回的是Handler
,使用Handler
发送数据 (关于ThreadLocal相关的,后面再加以补充)
接下来我们看一下Handler
发送数据dispatchMessage
这个方法
Handler (部分源码)
这里你可以看到
dispatchMessage(Message msg)
中有三种不同的调用
handleCallback(msg)
:这个是处理Handler.postxxx(Runnable r,xx)
发送的信息处理,最终回到用到r
的run
方法里面做逻辑处理handleMessage(msg)
跟mCallback.handleMessage(msg)
:都是用于处理Handler.sendxxx()
发送的信息,不同点在于,实例化Handler
有没有传入mCallback
对象,有的话则在mCallback.handleMessage
进行逻辑处理,没有的话则在handleMessage
进行逻辑处理
看一下Message
这个类的一些属性
Message(部分源码)
Message
拥有Handler
对象,所以来自不同的Handler
对象发送的Message
信息将自己也传入进来。
###总结
Handler并将本身传入到Messag中并发送到MessageQueue中,Looper开启轮训不断轮训MessageQueue的消息,将Message取出并使用Handler对象回调其本身的方法去进行逻辑操作。 Looper: 在第一次实例化的时候存到ThreadLocal变量中,并且获取的时候有则返回无则创建,所以一个线程只存在一个Looper。 MessageQueue: 是在Looper的构造函数中创建的,并且作为其成员变量,一个线程有且只有一个MessageQueue Handler: 可以创建多个,线程中并没有限制其创建的个数,并且在Message中挟持着对应的Handler,所以不同的Message会对应交由自己的挟持的Handaler进行逻辑的操作
Handler各种面试题一览
(大家可以参考一下网友的这篇文章)