Published on

Re-implement the works

Authors

前两天读到某某教授的一篇文章 "How to read paper",作者提出一个“3遍阅读法(3-pass reading)”,最后一遍的要求叫"re-implement"。这个词特别好。我们读文章时,或者因为使用某些知其然,不知其所以然的类库,知识时往往开始觉得很困惑,经常用错。源于我们对内在的原理不了解。而“re-implement”要求我们从原作者的思维触发,重铸作品,达到知其所以然的目的。当自己从头开始完全重铸意见作品时,就能明白其中很多的条件和假设,以及各种限制。这些往往在我们使用是会忽略的因素。大多数情况下,一个工具,一套理论,一个开发类库,都由其适用的条件和环境。或许作者没有说清楚,或者使用者没有仔细弄明白说明文档,往往很容易用错。

这点对于程序员来说更甚。往往拿到一个类库,不会仔细阅读说明,而是简单按照函数名称做一个猜测,忽略它的限制条件。很多bug就是由此引入的。这些类库正常情况下使用良好,然后在某些极端情况下会出问题。带来各种bug。

由"re-implement"一次我想到说其实类的设计充满这妥协和限制。一个好的程序员应该站在类库作者的角度来考虑这些问题。简单说,即使不要求完全重写类库,也应该在心里过一遍如果是自己来设计,会如何做。有条件的情况下,多读读类库的源码。一定会有很多收获。

Android中的AsyncTask就是这么一个很容易出错的类。这个类 android.os.AsyncTask 位于 android.os 包下,虽然其实更应该是一个 util 类。这个类本是为了方便程序员写异步操作而设计,然后它的API本省非常长。而且在说明里告诉说这个类不适合长时间运行的任务,结果给出的例子就叫做 DownloadingTask。这是一个设计很糟糕的类。

对于它的设计,如果没读过源码,可能会觉得有什么特别的,因为位于 android.os 中。然而它就是 HandlerThreadPool 的简单封装而已。

  • <1.6 单线程
  • 1.6-3.0 多线程
  • >=3.0 单线程

代码中使用了 SerialExecutorThreadPoolExecutor,有一个 sDefaultExecutor 静态成员变量来控制,可以通过 setDefaultExecutor 函数来控制。

所有的回调函数都是通过 HandlersendMessage 来实现。非常简单,是不是?

另外,ThreadPool中初始化时定义最大128个,同时5个thread执行。

Looper

Looper是线程见消息同步的机制。一个线程发生了某件事情,如何实时通知另外一个线程?这是一个通用问题。常见做法是有一个线程一直死循环,检查一个变量,另外的线程发生什么事情就写这个变量。一直死循环在检查变量的线程就是Looper线程。Android中UI线程就有一个Looper,当把本身的事情都做完之后,就会开始死循环,一旦有消息,在死循环里完成那个消息触发的事件,继续死循环。

Android线程相关

  • Handler, Message, Messenger, Process, AIDL, binder
  • AsyncTask
  • Thread
  • Runnable
  • ThreadPool