简述
Handler解决多线程问题(主线程才能修改UI界面),子线程可以通过Handler与主线程通信来更改UI界面。
作用
- 子线程发送消息
- 主线程中获取、处理消息
方法及作用
方法 | 作用 |
---|---|
handleMessage | 处理消息,重写该方法实现对消息的处理工作 |
hasMessage | 检查消息队列中是否有指定消息 |
sendEmptyMessage | 发送空消息 |
sendMessage | 发送消息 |
sendEmptyMessageDelayed | 延迟(毫秒)发送空消息 |
sendMessageDelayed | 延迟(毫秒)发送消息 |
removeMessages | 删除消息队列存在的指定消息(全部) |
Hanlder、Loop、MessageQueue
- Hanlder发送和处理消息
- MessageQueue保存消息,并且以先进先出的方式管理消息(线程必须要有MessageQueue才可以正常使用Hanlder)
- Looper:循环读取MessageQueue中的消息,并且交给对应的Handler处理(每一个线程只能拥有一个Looper)
在主线程中,系统以及初始化了Looper对象,因此主线程中可以直接创建使用Handler。而在子线程中,我们需要自行创建Looper对象。
private Looper()
{
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
在Looper的构造方法中会创建MessageQueue,然而该构造函数是私有的,无法调用。想要创建Looper对象,需要调用它的prepare方法,prepare方法中会进行判断,保证当前线程中只有一个Looper对象。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在创建Looper对象之后,需要调用它的loop方法开启循环提取消息。loop方法为一个死循环,会不断的获取MessageQueue中的消息,并且指派给相应的Handler。
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
线程中Looper使用步骤
- 调用 Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。
- 有了Looper之后,创建Handler子类的实例,重写HandlerMessage()方法,该方法负责处理来自其它线程的消息。
- 调用Looper的loop()方法启动Looper。