Android 开发艺术探索笔记(21)
loop 是一个死循环,唯一跳出循环的方式是 MessageQueue 的 next 方法是 null。当没有消息时,next 会一直阻塞,导致 loop 也一直阻塞。如果 next 返回了新消息,则用 dispatchMessage 去处理,而这个方法是在创建它 Handler 的 Looper 中执行的,这样就成功的将代码逻辑切换到指定的线程中去了。
Handler 的工作原理
Handler 的主要作用是发送和接收过程。post 最终也是通过 send 来实现的,sendMessage 的源码就是在 MessageQueue 中添加一条信息,然后 MessageQueue 就会通过 next 将这条信息交给 Looper,最后由 Looper 交由 Handler 处理,即调用了 Handler 的 dispatchMessage。
dispatchMessage 先检查 msg 的 callback 是否为 null,不为 null 就通过 handleCallback 来处理信息。Message 的 callback 是一个 Runnable 对象,实际上就是 Handler 的 post 方法所传递的 Runnable 参数。handleCallback 的逻辑就是运行这个 Runnable。接着检查 mCallback 是否为 null,不为 null 就调用 mCallback 的 HandleMessage 方法来处理消息。最后通过 Handler 的 HandleMessage 来处理消息。整个过程如下流程图:
主线程的消息循环:
ActivityThread 通过 ApplicationThread 和 AMS 来进行 IPC,AMS 以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 的 Binder 方法,然后 ApplicationThread 会向 H 发出信息,H 收到消息后会将 ApplicationThread 的逻辑切换到 ActivityThread 中去执行,即切换到主线程中执行。这个过程就是主线程的消息循环模型。
Android 的线程和线程池
在 Android 中,除了 Thread 可以扮演线程,AsyncTask、HandlerThread 和 IntentService。
线程池缓存了一定数量的线程,可以避免频繁的创建和销毁线程所带来的系统开销。主要通过 Executor 来派生特定类型的线程池。
AsyncTask
AsyncTask 是一个轻量级的异步任务类,它可以在线程池中执行任务,然后将结果传递给主线程更新 UI。AsyncTask 封装了 Handler 和 Thread。但它并不适合特别耗时的线程操作。
AsyncTask 是一个抽象泛型类,它提供了 Params、Progress、Result 三个泛型参数。Params 表示参数的类型,Progress 表示后台执行任务的进度、Result 表示后台任务返回结果的类型。它有 4 个核心方法:
(1)onPreExecute(),在主线程中执行,做准备工作。
(2)doInBackground(Params…params),在线程池中执行,执行异步任务,参数列表为输入参数,在这个方法中可以用 publishProgress 方法来更新任务的进度,publishProgress 会调用 onProgressUpdate 方法。此方法需要返回计算结果回 onPostExecute。
(3)onProgressUpdate,在主线程进行。后台任务进度改变后此方法调用。
(4)onPostExecute(Result result),在主线程运行。
还有 onCancelled 方法,在主线程进行,当异步任务取消时,此方法调用,onPostExecute 方法不会被调用。
使用 AsynceTask 只需创建一个内部类来继承 AsynceTask 然后重写上述方法就行了,然后将这个类实例化并执行 execute 方法就 OK。
AsyncTask 的使用条件:
(1)必须使用在主线程
(2)其对象必须在主线程中创建
(3)execute 必须在 UI 线程中调用
(4)不要在程序中直接调用那 4 个核心方法
(5)一个 AsyncTask 对象只能使用一次,即只能调用一次 execute 方法,否则会报错。
(6)我们可以使用 AsyncTask 的 executeOnExecutor 方法来并行的执行任务。
评论