Handler 是一个很好的工具,但并非 Android 平台特有的技术。我们对比一下 Handler 和线程池,可以说 Handler 模型其实很像一个 singleThreadPool,我们来对比一下 MyHandler(简化版 Handler) 和 newSingleThreadExecutor 方法:
// My Handler
class MyHandler {
private val threadLocal: ThreadLocal<BlockingQueue<Runnable>> = ThreadLocal()
private val blockingQueue: BlockingQueue<Runnable> = threadLocal.get() ?: LinkedBlockingQueue()
fun postRunnable(runnable: Runnable) = blockingQueue.put(runnable)
fun loop() {
while (true) blockingQueue.take().run()
}
}
// 1. Executors.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// 2. Executor
public interface Executor {
void execute(Runnable command);
}
// 3. 简化inline版 ThreadPoolExecutor.runWorker
final void runWorker(Worker w) {
while (task != null || (task = workQueue.take()) != null) {
task.run();
}
}
同样是一个线程,都有用于缓存任务的 LinkedBlockingQueue,part2 中 Executor.execute 并非马上执行,而是等同于 MyHandler 的 postRunnable 把任务加到队列里面。part3 中 runWorker 等同于 MyHandler 的 loop,都是单个线程作为消费者不断的消费一个阻塞容器中的任务。postRunnable 生产,Loop 消费。
以 Android 为例,交互事件、传感器回调等就是生产者,通过 Handler post 事件到主线程的 MessageQueue,MainLooper 按一定顺序消费这些事件。如果其中一个事件耗时过长(超过16ms),就可能导致一次可感知的(如果用户没在交互,或者没有动画等预期界面变化,则用户无法感知)卡顿,这就是我们不能在主线程上做网络请求的原因。我们需要把耗时任务流转到后台线程(对应的把与用户交互的主线程叫做前台线程),当后台线程完成耗时任务后再把任务流转回前台线程做进一步的非耗时处理。