Android Handler 消息机制
一、用于线程间通讯 (进程可以包含一到多个线程,进程和线程的本质区别是能否共享资源)
二、子线程UI操作 都是通过Handler实现 (UI线程不是线程安全的,不能在子线程进行处理)
1. Handler的post()方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
2. View的post()方法
当View没有被attach到window的时候,最后runnable的处理不是通过MessageQueue,而是ViewRootImpl自己在下一个performTraversals到来的时候执行,也就是说会延时执行,
getRunQueue().executeActions(mAttachInfo.mHandler);
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
3. Activity的runOnUiThread()方法
@Override
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
三、消息机制
- Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;(what / arg1 / arg2 / obj)
-
MessageQueue:消息队列的主要功能向消息池投递消息(
MessageQueue.enqueueMessage
)和取走消息池的消息(MessageQueue.next
);读取会自动删除消息,单链表维护,在插入和删除上有优势。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。 -
Handler:消息辅助类,主要功能向消息池发送各种消息事件(
Handler.sendMessage
)和处理相应消息事件(Handler.handleMessage
); -
Looper:不断循环执行(
Looper.loop
),按分发机制将消息分发给目标处理者。
Looper.prepare() 每个线程只能执行一次, 会创建Looper对象,Looper对象实例化时会创建MessageQueue
prepare(true)
,表示的是这个Looper运行退出,而对于false的情况则表示当前Looper运行时不允许退出。
如果是在子线程里实例化一个Handler,需要主动调用Looper.prepare()
ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。TLS常用的操作方法:
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper#prepareMainLooper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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()
/*package*/ Handler target;
/*package*/ Runnable callback;
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
try {
msg.target.dispatchMessage(msg);
} finally {
}
msg.recycleUnchecked();
}
}
Handler#dispatchMessage() 分发消息调用callback.
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
1:message.callback.run() msg的callback是个runnable对象
Handler#handleCallback()
private static void handleCallback(Message message) {
message.callback.run();
}
2:mCallback.handleMessage mCallback是handler实例化时传递过来的接口
Handler 实例化
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
3:handleMessage() 子类实现handler时需要重写的方法
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
ActivityThread是App的入口,main里做了死循环的操作,为啥没有卡死呢?
https://www.zhihu.com/question/34652589
thread.attach(false);便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程
主线程的死循环一直运行是不是特别消耗CPU资源呢? 其实不然,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:
在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。
上一篇: 算法之深度优先寻路
下一篇: 数据结构与算法_深度优先寻路