首先是要明白,Android UI 是线程不安全的,在 UI 线程中不可以执行耗时操作,在子线程中不可以更新 UI。
所以就需要我们在子线程去做耗时操作,在 UI 线程中去更新UI。
异步消息
Handler Looper Message MessageQueue
首先明白这个类的作用
Handler 用来操作消息的(包括,发送和处理)
Looper 用来控制消息的循环,一个线程对应一个Looper
Message 封装消息的实体
MessageQueue 消息队列,用来存放消息的 一个Looper对应一个消息队列
明白Handler使用的条件
在使用Handler之前,必须调用Looper.prepare();这个方法。否则会抛一个运行时异常:Can't create handler inside thread that has not called Looper.prepare()
剖析
在Handler的构造方法中
通过
mLooper = Looper.myLooper();
得到一个Looper对象
进入到myLooper()方法
return sThreadLocal.get(); sThreadLocal 是一个 存放 Looper 的 ThreadLocal
这样就从当前线程当中去取一个Looper对象
如果sThreadLocal 为null 则得不到 Looper对象
现在再来看Looper.prepare();
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper()); new一个Looper对象存放在ThreadLocal 当中
在这个方法中解决了俩个问题
1.一个线程当中只对应一个Looper对象
2.在使用Handler之前必须调用Looper.prepare();
这个时候,好多人会有一个疑问,就是在UI线程里面使用Handler的时候,也没有使用Looper.prepare();这个方法
android在启动的时候,其实首先是先去调用UI线程 ActivityThread 然后通过main()入口,启动应用程序
在main()方法中
Looper.prepareMainLooper();
在prepareMainLooper()方法中
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
所以在UI线程中,系统已经为我们设置好了Looper对象
Handler 在 发送消息的时候 ,除了使用sendMessageAtFrontOfQueue()这个方法,其他方法最后都会调用sendMessageAtTime() 这个方法去发送消息
sendMessageAtTime() 接收俩个参数
sendMessageAtTime(Message msg, long uptimeMillis)
msg 就是我们要发送的消息
uptimeMillis 是发送消息的时间 = 系统当前时间 + 发送消息延时的时间
在这个方法里面实现的消息的入队操作 enqueueMessage()。
在这个方法中
系统并没有把所有消息都存放在集合中,只是使用了一个变量来记录当前要发送的消息。
出队
Looper.loop()
通过队列的操作,不断的通过next() 得到消息
如果消息不为null
则
msg.target.dispatchMessage(msg);
msg.target 其实就是 Handler 对象
在dispatchMessage() 方法中,判断回调接口是否为空
不为空
则
调用mCallback.handleMessage(msg)