Handler机制

Handler机制

Posted by candy1126xx on April 23, 2017

功能

使用“消息队列“,解决线程间/进程间同步问题;封装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()中:

  1. 为Message加上FLAG_IN_USE;
  2. 为Message.when赋值;
  3. 把Message按when排序加入队列(主要是Message.next的赋值);
  4. 通知Native层管道的写入端“已经写入数据了”(nativeWake());

MessageQueue运转

在Looper.loop()中:

  1. 如果上次“时间差”不为0,Binder.flushPendingCommands();
  2. 使线程阻塞“时间差”的时间(nativePollOnce());若时间差为-1,则为一直阻塞,直到有新的消息到来(nativeWake());
  3. 如果下一个Message是null,即队列已经空了,记录“时间差”为-1,返回1;
  4. 如果下一个Message是同步分隔栏,找其后第一个异步消息;
  5. 检查当前时间是否到了Message.when,
  6. 如果没到,
    • 如果有IdleHandler,则处理IdleHandler,记录“时间差”为0,返回1;
    • 如果没有IdleHandler,则记录“时间差”为when - now,返回1;
  7. 如果到了,从队列中删除这个Message,并加上FLAG_IN_USE;
  8. 调用Message.Handler.dispatchMessage()处理消息。

处理Message

“Handler处理Message的过程“运行在工作线程;“插入”和“处理”是同一个Handler在不同线程(同时可能是不同进程)执行的;MessageQueue的同步保证了“插入”和“处理”的同步;在Handler.dispatchMessage()中:

  1. 如果Message.callback不为空,执行callback;
  2. 否则,如果Handler.mCallback不为空,执行mCallback;
  3. 如果Handler.mCallback为空,或mCallback返回true,执行Handler.handleMessage()。

阻塞任务

调用Handler.runWithScissors(),可实现调用线程阻塞,直到任务完成。其实现过程是:

  1. 先检查调用线程是否是Handler工作线程,如果是,执行Runnable;
  2. 否则,把Runnable封装成BlockingRunnable;
  3. 在BlockingRunnable中,用“内置锁+while组合“,实现“调用线程一直处于等待阻塞状态,直到BlockingRunnable.run()调用“。

延时任务

延时任务的实现是依赖MessageQueue的休眠。见上面《MessageQueue运转》中第2步的nativePollOnce(),对 应Native层android_os_MessageQueue_nativePollOnce(),最终调用到Linux系统调用epoll_wait()。