一、我们都知道Android开发中必须把所有的UI操作放在主线程中,如果直接在子线程中操作UI,APP会报错崩溃。
那么Android为什么要这样做呢?
由于UI使用多线程模型将会面对海量的死锁问题,同时加锁造成的性能下降也使其效率让人难以接受,使用单线程模型仍然是目前的最佳选择。so Android中的UI采用的是单线程模型。
二、Message,MessageQueue,Handler,Looper之间的关系
三、源码分析Message
android.os.Message的主要功能是进行消息封装。
1、
数据在Intent数据传递,以及在进程间通信(IPC)需要实现序列化,Message实现了Parcelable接口,因此支持Intent数据传递,也支持进程间通信(IPC)。
what:标识信息,定义此Message对应什么操作
arg1、arg2:传递简单数据
obj:定义此Message传递的信息数据
2、
flags:标识信息,Message的使用状态,取值:FLAG_IN_USE、FLAG_ASYNCHRONOUS、FLAGS_TO_CLEAR_ON_COPY_FROM
when:记录Message投递时间
when值=Handler对象的sendMessageAtTime方法中第二个参数,如上部分data:Bundle数据,能用message.getData()、peekData()、setData(Bundle data)方法设置/获取
target:保存当前投递Message/处理Message的Hander对象
赋值时机在Handler对象的enqueueMessage方法中callback:Handler对象post方式发出的Message回调方法对象
此Runnable即作为Message中的回调对象callback值 在looper分发Message时调用相应的Handler.dispatchMessage()方法,callback会在handleCallback方法中调用3、
根据next和sPool属性以及MAX_POOL_SIZE常量能够看出Message被设计为大小为50的单向链表数据结构,内部保存了一个缓存消息池。
next:消息链中的下一条消息,没有则为null,称之为尾元素,它总是指向链表中后一个对象
sPool:当前使用的Message对象地址,称之为头元素,它总是指向链表中最新的对象
sPoolSize:当前缓存池中链表数据大小
MAX_POOL_SIZE:最多缓存大小
gCheckRecycle:回收Message时用到,且targetSdkVersion<21时永远false
四、源码分析Handler
1、Handler的任务
(1)发送消息到对应Looper的消息队列
(2)处理从消息队列中取出的消息
2、先来看看Handler的7个构造方法
Handler()、Handler(Callback callback)、Handler(Looper looper)、Handler(Looper looper, Callback callback)、Handler(boolean async)、Handler(Callback callback, boolean async)、Handler(Looper looper, Callback callback, boolean async)
Handler()、Handler(Callback callback)、Handler(boolean async)三个构造方法实际调用Handler(Callback callback, boolean async)构造方法
Handler(Looper looper)、Handler(Looper looper, Callback callback)两个构造方法实际调用Handler(Looper looper, Callback callback, boolean async)构造方法
源码看起来都是为了给mLooper,mQueue,mCallback,mAsynchronous四个成员变量赋值;
mLooper:某线程创建的Looper对象,Handler通过保存mLooper对象与该Looper所在的线程建立联系
mQueue:获得Looper对象中的消息队列,以便Handler发送/移除消息队列中的Message
mCallback:处理Message的回调方法
mAsynchronous:异步消息,只有一个作用,就是在设置Barrier时仍可以不受Barrier的影响被正常处理,如果没有设置Barrier,异步消息就与同步消息没有区别,可以通过removeSyncBarrier移除Barrier
3、Handler发送消息的方式
以上12种方式最终会handler.enqueueMessage()方法,该方法中通过调用mQueue.enqueueMessage()方法入队4、Handler处理消息 handler.dispatchMessage()
处理优先级:msg.callback>handler.mCallback>handler.handlerMessage()五、源码分析Looper
1、分析Looper前需要理解ThreadLocal,ThreadLocal用于线程间的数据隔离。
sThreadLocal:静态变量sThreadLocal为每一个创建了Looper的线程保存了一份(Thread-Looper)值
sMainLooper:UI线程Looper,可通过getMainLooper()、myLooper()获取
mQueue:维护一个独立的消息队列
mThread:mThread = Thread.currentThread();当前创建Looper的线程;
mTraceTag:跟踪标记
2、线程如何创建Looper
(1)UI线程创建Looper,ActivityThread中调用Looper.prepareMainLooper()方法初始化UI线程的Looper,调用Looper.loop()方法在这个线程中运行消息队列。
(2)普通线程创建Looper略有不同,线程中调用Looper.prepare()方法初始化UI线程的Looper,调用Looper.loop()方法在这个线程中运行消息队列。
3、Looper工作原理
Looper.loop()很重要,Handler、Looper、Message都是在这个方法里建立联系;
讲Handler的时候我们说了Handler调用mQueue.enqueueMessage()入队,那么在looper里Looper做个死循环,不断的调用queue.next()出队,当消息为空的时候,Looper中的消息队列会成阻塞状态,等待消息的到来,当消息不为空的时候,会通过Looper发送对应消息给Handler的dispatchMessage()方法进行处理,这里的msg.target就是之前提到的Handler。
哎,花了挺长时间写,第一次写博客希望大家多多指教。
网友评论