功能
使用“消息队列“,解决线程间/进程间同步问题;封装Binder机制,实现进程间通信。
重要的类
- Looper:封装了一个MessageQueue;可以为某个线程添加一个MessageQueue,并使其运转起来;另外还可以插入/删除“同步分隔栏”;“同步分隔栏”也是一个Message,但是Message.target是null。
- prepare():为调用线程添加一个MessageQueue。
- loop():使调用线程的MessageQueue运转起来。postSyncBarrier():插入同步分隔栏;插入后,不再处理队列中的同步消息,只处理异步消息;虽然不处理同步消息了,但是同步消息并没有被删除,删除同步消息栏后,一个不少还是会处理。 - removeSyncBarrier():删除同步分隔栏。
- MessageQueue:使用单链表保存“消息队列”;暴露了添加和删除“消息”的方法;
- mQuitAllowed:
- mPtr:Native层消息队列(NativeMessageQueue对象)的地址。
- mMessages:队头。
- Message:一条消息。
- callback:处理消息之一。
- flags:FLAG_ASYNCHRONOUS标记此Message为异步消息。
- next:指向下一条消息,以此构成消息链表。
- Handler:一个MessageQueue对应一个Handler;封装了向MessageQueue插入Message的过程;由于它的引用被Message保存,而Message的引用由MessageQueue保存,所以它的生命周期与MessageQueue相同;为防止组件内存溢出,会使用static修饰Handler,以区分组件和被Handler引用的组件成员变量的生命周期;需要实现handleMessage方法以自定义处理消息逻辑;必须在主线程创建,同时指定它的mLooper域是工作线程的Looper。
- mCallback:处理消息之二。
- handleMessage():处理消息之三。
- mAsynchronous:如果为true,那么用该Handler插入的消息全部为异步消息。
- obtainMessage():封装出一个Message。
- sendXXX():向MessageQueue插入一条Message;随后执行的是Handler.mCallback或Handler.handleMessage()。
- postXXX():向MessageQueue插入一条Message;随后执行的是Message.callback。
- runWithScissors():借助BlockingRunnable实现阻塞任务。
- IdleHandler:当队列中有延时消息,导致线程进入阻塞状态前,需要执行的动作。
- MessengerImpl:实现了IMessenger接口;是Handler机制进程通信的服务端。
- Messenger:MessengerImpl的装饰类,实现了Parcelable接口,以跨进程传输。
MessageQueue的线程安全
- 使用ThreadLocal把MessageQueue保存到线程本地储存。
- MessageQueue的所有暴露的方法都使用了内置锁。
插入Message
“Handler向MessageQueue插入Message的过程“运行在主线程,在Message.enqueueMessage()中:
- 为Message加上FLAG_IN_USE;
- 为Message.when赋值;
- 把Message按when排序加入队列(主要是Message.next的赋值);
- 通知Native层管道的写入端“已经写入数据了”(nativeWake());
MessageQueue运转
在Looper.loop()中:
- 如果上次“时间差”不为0,Binder.flushPendingCommands();
- 使线程阻塞“时间差”的时间(nativePollOnce());若时间差为-1,则为一直阻塞,直到有新的消息到来(nativeWake());
- 如果下一个Message是null,即队列已经空了,记录“时间差”为-1,返回1;
- 如果下一个Message是同步分隔栏,找其后第一个异步消息;
- 检查当前时间是否到了Message.when,
- 如果没到,
- 如果有IdleHandler,则处理IdleHandler,记录“时间差”为0,返回1;
- 如果没有IdleHandler,则记录“时间差”为when - now,返回1;
- 如果到了,从队列中删除这个Message,并加上FLAG_IN_USE;
- 调用Message.Handler.dispatchMessage()处理消息。
处理Message
“Handler处理Message的过程“运行在工作线程;“插入”和“处理”是同一个Handler在不同线程(同时可能是不同进程)执行的;MessageQueue的同步保证了“插入”和“处理”的同步;在Handler.dispatchMessage()中:
- 如果Message.callback不为空,执行callback;
- 否则,如果Handler.mCallback不为空,执行mCallback;
- 如果Handler.mCallback为空,或mCallback返回true,执行Handler.handleMessage()。
阻塞任务
调用Handler.runWithScissors(),可实现调用线程阻塞,直到任务完成。其实现过程是:
- 先检查调用线程是否是Handler工作线程,如果是,执行Runnable;
- 否则,把Runnable封装成BlockingRunnable;
- 在BlockingRunnable中,用“内置锁+while组合“,实现“调用线程一直处于等待阻塞状态,直到BlockingRunnable.run()调用“。
延时任务
延时任务的实现是依赖MessageQueue的休眠。见上面《MessageQueue运转》中第2步的nativePollOnce(),对 应Native层android_os_MessageQueue_nativePollOnce(),最终调用到Linux系统调用epoll_wait()。