一、什么是handler?
handler是Android给我们提供用来更新UI的一套机制,也是消息处理机制。
二、为什么要使用Handler
一个Android应用程序被创建时就会创建一个进程,该进程用应用的包名作为进程名。该进程会启动主线程ActivityThread,也叫做UI主线程,但有时需要做些耗时操作,为了不能够去阻塞UI主线程的正常运行,我们将它放在子线程中进行操作,操作完成后需要绘制UI,但Android子线程不能直接操作UI线程的,所以通过Handler来进行通信
三、为什么Android子线程不能直接操作主线程?
Android UI线程不是线程安全的,如果多线程并发的话就会造成界面混乱,不可控的状态。那为什么不能让主程序加上锁机制,这样就能够线程安全了?可上锁就会有造成访问的逻辑变得很麻烦、很复杂,并且会阻塞其他线程的执行,导致性能下降。综上问题,Android采用单线程模型来处理UI操作。
Handler中五个重要的类
- Handler:负责发送和处理消息。
- Message:用来携带需要的数据。
- MessageQueue:消息队列,内部存储结构是采用单链表的数据结构来存储消息列表的,其中主要有插入enqueue()和从中拿走并删除next()两个方法。
- Looper:消息轮巡器/消息泵/消息循环,不停的从MessageQueue中取Message。以无限循环的方式去查找是否有新消息,如有就去处理,若没有就standby(等待)。
- ThreadLocal: 让当前线程与looper绑定 并确保只有一个
Handler的消息处理机制
一、Handler
由于Handler主要负责发送和处理消息,那我们主要实现它的sendMessage、handlerMessage、dispatchMessage三个方法,来处理消息的发送和接收:
sendMessage:把当前Handler和Message绑定 然后发送到MessageQueue
当然源码里是这样写的 :
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
可以看到 无论是send什么Message 最后是返回sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
sendMessageAtTime返回的是enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
enqueueMessage方法中的 msg.target = this 就是把当前handler和Message绑定在一起
然后返回的又是MessageQueue里面的enqueueMessage方法 这个方法会把Message储存进MessageQueue中
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- 我们在Handler的构造函数中获取当前线程对应的looper,并取出Looper中对应的消息队列保存在成员变量中。
- sendMessage方法中我们给Message的target变量赋值为this,也就是表明了Message是由当前的Handler来负责处理的,
- 之后调用enqueueMessage方法将消息存入消息队列中。
- 而dispatchMessage方法我们实现比较简单,负责调用handleMessage来处理消息。
二、Looper
Looper主要负责取出消息交由Handler处理,我们主要来实现prepare、loop方法:
Looper.myLooper()
从当前线程中的ThreadLocal中取出Looper实例。如果Looper为null的话就会抛异常,抛出的异常内容翻译过来就是
无法在未调用Looper.prepare()的线程内创建handler
所以 在调用Looper.myLooper()之前必须要先调用Looper.prepare()方法
Looper.prepare();
prepare() 方法中则是实例化了一个Looper,然后将Looper放进进ThreadLocal中
在我们调用Looper.prepare方法时也将MessageQueue实例化了
ThreadLocal
ThreadLocal.set方法是把当前looper存入Threadlocal中与当前线程绑定
在调用Looper.myLooper方法之前必须必须已经调用了Looper.prepare方法,即在实例化Handler之前就要调用Looper.prepare方法
主线程中Android系统已经帮我们调用了Looper.prepare方法
Looper.loop() :从MessageQueue中取出消息然后发给Handler处理
该方法中有个死循环
循环里面 MessageQueue的next方法取出消息
然后调用消息的 .target.dispatchmessage方法
target是与Message绑定的handler
dispatchmessage是handler的方法里面调用了HandlerMessage方法处理消息
三、Message
message里面有个target值 是用来绑定handler方法的
四、MessageQueue
这里的next和enqueueMessage是典型的生产者、消费者的关系,为防止出现错乱我们给两个方法都加上Lock锁,当enqueueMessage方法存放消息时如果当前队列消息满了,则调用mFullQueue.await();进行等待消息处理,当向消息队列中存放消息后,也就是说消息队列不为空了,调用mEmptyQueue.signalAll();通知next()方法来处理消息。
1、Handler的工作原理
在使用Handler之前必须要调用Looper.prepare()这句代码,这句代码的作用是将Looper与当前的线程进行绑定,在实例化Handler的时候,通过Looper.myLooper()获取Looper,然后再获得Looper中的MessageQueue。在子线程中调用Handler的sendMessage方法就是将Message放入MessageQueue中,然后调用Looper.loop()方法来从MessageQueue中取出Message,在取到Message的时候,执行 msg.target.dispatchMessage(msg);这句代码,这句代码就是从当前的Message中取出Handler然后执行Handler的handleMessage方法
2、Handler、Message、MessageQueue以及Looper之间的关系
它们的关系如下图(图片来源于网上)
Android在子线程更新UI的最常见的五种方式 (这里不讲解AsyncTask(异步任务))
1、runOnUiThread()方法
2、handler.post()方法
3、handler.sendMessage()方法
4、view.post()方法。
5、view postDelayed(Runnable,long)
前四种是慕课网老师讲解的,最后一种是疯狂Android讲义书籍上有的一种