Solobear 述而不作

Android消息机制与多线程


android中的消息机制


Handler、Looper和MessageQueue:

  • Message被包装在Looper中,且Looper是线程相关的,每个线程只有一个Looper
  • UI主线程的启动参见framework中的ActivityThread.java,在main(String[] args)函数中启动了Looper.loop消息循环
  • 新建一个Handler对象后,在Handler类的构造函数中会将Handler对象与所在线程关联,因此Handler对应了所在线程的Looper
  • Handler的sendMessage向所关联的消息队列发送message,message内则包含了对应的消息处理的target:Handler
  • Looper.loop循环中,message执行了回调message.target.dispatchMessage(message),进而调用了使用者所Overrdie的Handler.handleMessage()方法

AsyncTask异步框架

  1. 构造函数中的几个泛型参数中:Params...params是执行AsyncTask.execute(Params...)时使用的参数,实际上传入doInBackground(Params...)作为参数; Progress... values表示进度,可在调用publishProgress(Progress...)时将进度送至主消息循环中;进度同样会传入用户override的onProgressUpdate(Progress)作为方法参数; Result result是后台任务方法doInBackgroun(Params...)的返回值,即任务结果,作为onPostExecute(Result)方法的参数。

  2. new AsyncTask().execute(Params...params):UI线程中调用,触发异步任务AsyncTask

  3. @Override onPreExecute():在UI线程中执行,异步任务启动前的准备工作

  4. @Override doInBackground(Params...):在任务子线程中执行,通常用于理耗时任务。在此方法中用户可以自行调用 publishProgress(Progress...),发送MESSAGE_POST_PROGRESS消息至主线程,进而触发主线程中的方法onProgressUpdate(Progress...)

  5. @Override onProgressUpdate(Progress...):后台任务调用了publishProgress()后,主线程对消息的回应处理,可用于更新UI

  6. @Override onPostExecute(Result):任务子线程执行完毕后触发结束消息的处理方法,收尾工作。


看看源码(API23)

AsyncTask将Handler、Looper和MessageQueuq进行了包装,用线程池执行后台任务。因此主要来看后台任务 FutureTask、消息处理 Handler以及 ThreadPoolExecutor是如何设计的:

  • Handler:

    构造了InternalHandler, 其构造函数获取MainLoop,即Handler是和主线程消息循环绑定的。消息处理方法handleMessage则对MESSAGE_POST_RESULTMESSAGE_POST_PROGRESS消息做出了响应。

  • FutureTask

    AsyncTask构造函数创建了Callable类型的对象 mWorker,call()方法则包装了doInBackGround()方法,postResult()方法得到result并发送MESSAGE_POST_RESULT消息。当然,在doInBackground中则可以调用publishProgress(Progress...)。mWorker用于构造FutureTask类型 mFuture。mFuture就是任务执行体了。

    比较了几个版本的源码之后,我发现API22之后,Handler的创建是在mWorker 的call()方法中的postResult()方法中完成的, 采用了单例模式的getHandler()创建/获取InternalHandler。早期的版本(Android5.0)则在类的静态成员中就已经创建此Handler对象。尽管这里Handler的创建在子线程,但是由于其构造函数与主线程Looper绑定,因此消息处理仍然在主线程完成。

  • executors相关

    用户在主线程中调用execute(Params…parms)后,实际上执行了executeOnExecutor(sDefaultExecutor, params),此方法内首先执行onPreExecute(),随后则是执行任务过程:sDefaultExecutor.execute(mFuture)

    再来看看sDefaultExecutors, 这是一个SerialExecutor类的实例,其execute()方法用于维持一个任务队列,并将将Runnable放入mTasks队尾,随后Poll一个task送入THREAD_POOL_EXECUTOR执行。也就是说sDefaultExecutors只起到维护任务队列的过程,真正的执行体还是THREAD_POOL_EXECUTOR,这是一个线程池new ThreadPoolExecutor(...)

    值得注意的是,尽管将任务送入了线程池THREAD_POOL_EXECUTOR,但是SerialExecutor.execute()方法使用了同步锁,实质上是一个线性入队执行的单线程过程,从类名上也是可以看出来的:public synchronized void execute(final Runnable r),即使多个线程提交任务,也得一个一个来。这也是android3.0之后的变化,旧版本的AsyncTask是支持在线程池中多任务并发的。

    线程池的执行过程不再赘述,submit()和execute()最终都是调用了callable的call()方法。call()过程中发送的两类消息则可以被InternalHandler获取并得到相应处理。


Similar Posts

上一篇 第一篇博客

Comments