当前位置: 代码迷 >> 综合 >> Android 消息机制详解(源码分析ThreadLocal、Looper、Handler、AsyncTask)
  详细解决方案

Android 消息机制详解(源码分析ThreadLocal、Looper、Handler、AsyncTask)

热度:22   发布时间:2023-12-06 10:55:07.0

Android 消息机制

1 概述

Android 的消息机制主要是指 Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工作过程。

Android 应用是事件驱动的,每个事件都会转化为一个系统消息,即 Message 。消息中包含了事件相关的信息以及这个消息的处理人——Handler。每个进程中都有一个默认的消息队列(Message Queue,采用单链表的形式来存储消息列表),这个消息队列维护了一个待处理的消息列表,消息循环不断地从这个队列中取出消息、处理消息,这样使得应用动态地运作起来。

Message、MessageQueue、Looper、Handler的工作原理像是工厂的生产线,Looper是发动机,MessageQueue是传送带,Handler是工人,Message是待处理的产品。
在这里插入图片描述

消息通过Handler投递到消息队列,这个消息队列在Handler关联的Looper中,消息循环启动之后会不断地从队列中获取消息,其中消息的处理分为Native层和Java层,两个层次有自己的消息机制,Native层基于管道和epoll,而Java层则是一个普通的链表。获取消息后会调用消息的callback或者分发给对应Handler的handleMessage()处理。消息被处理之后会会受到消息池便于下次利用。

Handler 创建的适合会采用当前线程的 Looper 来构造消息系统。Handler 内部使用 ThreadLocal 获取当前线程的 Looper。ThreadLocal 可以在不同的线程中互不干扰的存储并提供数据。线程是默认没有 Looper 的,如果使用 Handler 就必须为线程创建 Looper。

Handler 的主要功能是将一个任务切换到某个指定的线程中去执行。这是因为 Android 规定访问 UI 只能在创建它的线程(大多数情况下 UI 都是从UI 线程中创建的),否则会抛出异常。(ViewRootImpl的checkThread()对UI操作做了验证:对UI控件的操作线程是否是创建它的线程)


系统为什么不允许在子线程中访问UI?

因为 android 的 UI 控件不是线程安全的,如果在多线程中并发访问可能会导致 UI 控件处于不可预期的状态。

为什么不对UI控件的访问加上锁机制? 缺点:

  • 让UI访问的逻辑变复杂
  • 降低UI访问的效率,会阻塞某些线程的执行

因此,单线程去处理UI控件的访问是最简单高效的。


使用 Handler:为当前线程创建 Looper 或者在有 Looper 的线程上。

  • post(Runnable r) 将runnable包装到Message中
  • sendMessage() (post最终也是调用send)

send() 被调用时,会调用MessageQueue的enqueueMessage将消息放到消息队列中。Looper 发现有新消息就会处理。最终 Runnable 或者 Handler 的 handleMessage() 就会被调用。


ThreadLocal

ThreadLocal ,也叫线程本地变量。是一个线程内部的数据存储类,可以在指定的线程中存储、获取数据。

应用场景:

  1. 以线程为作用域并且不同线程具有不同的数据副本。
    • Looper的作用域是线程,不同线程有不同的Looper。
      • 若不采用ThreadLocal,就要采用一个全局的HashMap实现LooperManager类
  2. 复杂逻辑下的对象传递。比如监听器的传递。
    • 监听器能贯穿整个线程的执行过程,在线程内部通过get()就能获得监听器。
      • 若不采用ThreadLocal,
        1. 将监听器通过参数的形式在函数调用栈中进行传递。(函数调用栈太深 ×)
        2. 将监听器作为静态变量供线程访问。(10个线程就有10个静态变量。采用 ThreadLocal ,每个监听器对象都在自己的线程内部存储)
class ThreadLocalTest {
    private ThreadLocal<Boolean> booleanThreadLocal = new ThreadLocal<>();public static void main(String[] args) {
    new ThreadLocalTest().test();}private void test(){
    booleanThreadLocal.set(true);System.out.println("main---"+booleanThreadLocal.get());new Thread("thread1--"){
    @Overridepublic void run() {
    booleanThreadLocal.set(false);System.out.println("thread1--"+booleanThreadLocal.get());}}.start();new Thread("thread2--"){
    @Overridepublic void run() {
    System.out.println("thread2--"+booleanThreadLocal.get());}}.start();}
}
//main---true
//thread1--false
//thread2--null

ThreadLocal实例实际上也是被其创建的类持有(更顶端应该是被线程持有)。而ThreadLocal的值其实也是被线程实例持有。

它们都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。

在这里插入图片描述

 public void set(T value) {
    Thread t = Thread.currentThread();//1.首先获取当前线程对象ThreadLocalMap map = getMap(t);//2.获取该线程对象的ThreadLocalMapif (map != null)map.set(this, value);//如果map不为空,执行set操作,以当前threadLocal对象为key,实际存储对象为value进行set操作elsecreateMap(t, value);//如果map为空,则为该线程创建ThreadLocalMap
}
    //Thread中的成员变量ThreadLocal.ThreadLocalMap threadLocals = null;		//每个Thread线程中都封装了一个ThreadLocalMap对象//ThreadLocal类中获取Thread类中的ThreadLocalMap对象ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;}//ThreadLocal类中创建Thread类中的ThreadLocalMap成员对象void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);}

每一个Thread对象都有一个ThreadLocalMap对象,这样设计有两个目的:

  1. 可以保证当前线程结束时,相关对象可以立即被回收;
  2. ThreadLocalMap元素会大大减少,因为Map过大容易造成哈希冲突而导致性能降低。
 public T get() {
    Thread t = Thread.currentThread();//1.首先获取当前线程ThreadLocalMap map = getMap(t);//2.获取线程的map对象if (map != null) {
    //3.如果map不为空,以threadlocal实例为key获取到对应Entry,然后从Entry中取出对象即可。ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();//如果map为空,也就是第一次没有调用set直接get(或者调用过set,又调用了remove)时,为其设定初始值
}

这样,实际上每个线程中都保存一份数据,Looper就是这样保存在自身当前的线程中的。这也是为什么Looper中的sThreadLocalstatic的,却能在不同的线程中获取到自己线程的Looper的原因。


2 MessageQueue 的工作原理

MessageQueue 只是一个消息的存储单元,不能处理消息。Looper 会以无限循环的形式去查询是否有新消息,有则处理,没有则等待。

其通过一个单链表来维护消息列表,单链表在插入和删除时有优势。

MessageQueue 主要包含两个操作:

  • enqueueMessage():往消息队列插入一条消息(单链表的插入)
  • next():从消息队列取出一条消息并移除
    • 无限循环。如果消息队列没有消息就会一直阻塞在这里。当有新消息到来时,next()会返回这条消息并将它从单链表中移除。

3 Looper 的工作原理

3.1 Looper 的使用

Handler 的工作需要Looper,没有会报错。

Looper.prepare():为当前线程创建一个Looper

接着通过 Looper.loop() 来开启消息循环。

new Thread(){
    @Overridepublic void run() {
    Looper.prepare();Handler h = new Handler();Looper.loop();}
}.start();

prepareMainLooper()给ActivityThread创建Looper使用。

Looper.myLooper() 获取当前线程绑定的Looper,如果没有返回 null 。

Looper.getMainLooper() 返回主线程的 Looper ,这样就可以方便的与主线程通信。

Looper退出:

Looper.myLooper().quit();//直接退出Looper
Looper.myLooper().quitSafely();//设定一个退出标记,把消息队列中已有的消息全部处理完毕后再安全退出

Looper退出后,通过Handler发送的消息会发送失败,Handler的send()会返回false。

在子线程中,若手动创建了Looper,当所有事情完成后应退出Looper来终止消息循环,不然子线程会一直处于等待状态。退出Looper后,这个线程会立刻终止,建议在不需要的时候调用上述两个方法退出Looper。

3.2 Looper 底层原理

//Looper的作用域是线程,不同线程有不同的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//构造方法
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);//创建一个消息队列mThread = Thread.currentThread();//将当前线程的对象保存
}public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}public static @NonNull MessageQueue myQueue() {
    return myLooper().mQueue;
}

Looper.prepare():为当前线程创建一个Looper

public static void prepare() {
    prepare(true);
}private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
    throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));
}

Looper.loop() 来开启消息循环。

 public static void loop() {
    final Looper me = myLooper();if (me == null) {
    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}if (me.mInLoop) {
    Slog.w(TAG, "Loop again would have the queued messages be executed"+ " before this one completed.");}me.mInLoop = true;final MessageQueue queue = me.mQueue;//...for (;;) {
    //死循环Message msg = queue.next(); // might blockif (msg == null) {
    //当msg为空才跳出循环return;}//...}
}

loop()是一个死循环,唯一跳出循环的方式是 MessageQueue 的 next() 返回 null 。(当调用Looper的quit() 时会标记一个退出状态,MessageQueue的next也就会返回null)

MessageQueue 的 next() 也是一个死循环,当没有新消息时会阻塞在那里。所以 Looper 的 loop() 也会阻塞,因此死循环会一直持续。在完毕后必须退出Looper才能终止消息循环。

当MessageQueue的next返回了新消息,Looper会处理这个消息:msg.target.dispatchMessage(msg) (这里msg.target是发送这条消息的Handler对象),这样消息就又交给它的dispatchMessage()来处理(在Handler所在的线程处理),最终返回到 Handler 的 handleMessage(Message msg)处理。

4 Handler的工作原理

Handler 是 Android 消息机制的上层接口,在开发过程中只需和 Handler 交互即可。

4.1 Handler简单应用

UI 不可以在不是它创建的线程里更新 -> 即 UI 不可以在子线程更新。

  1. post()
public class MainActivity extends Activity{
    Handler mHandler = new Handler(Looper.getMainLooper());private void dosomething(){
    new Thread(){
    @Overridepublic void run(){
    //耗时操作,得到结果//通过 Handler 将结果传到主线程,并更新UImHandler.post(new Runnable(){
    @Overridepublic void run(){
    //更新UI}});}}.start();}
}
  1. sendMessage()
public class MainActivity extends Activity{
    Handler mHandler = new Handler(Looper.getMainLooper()){
    @Overridepublic void handleMessage(Message msg) {
    switch (msg.what){
    //根据msg.what处理信息case 1:System.out.println("handleMessage thread id " + Thread.currentThread().getId());System.out.println("msg.arg1:" + msg.arg1);System.out.println("msg.arg2:" + msg.arg2);break;                  }}       };private void dosomething(){
    new Thread(){
    @Overridepublic void run(){
    //耗时操作,得到结果 Message msg = new Message();msg.what = 1;//出不同的Message,以便我们做出不同的处理操作msg.arg1 = 123;//可以通过arg1和arg2给Message传入简单的数据msg.arg2 = 321;//通过 Handler 将结果传到主线程,并更新UIHandler.sendMessage(msg);}}.start();}
}

4.2 Handler 原理

就上面的例子来说,通过 Handler 传递了一个 Runnable 给UI线程。实际上 Runnable 会被包装到一个 Message 对象中,然后再投递到UI线程的消息队列。

public final boolean post(Runnable r){
    return sendMessageDelayed(getPostMessage(r),0);//再将这个对象传给 sendMessageDelayed()
}private static Message getPostMessage(Runnable r){
    Message m = Message.obtain();//obtain()会从被回收的对象池中获取Message对象(回收指将Message对象不使用时会被回收到消息池中)没有则新建m.callback = r;//将Runnable包装到一个 Message 对象中return m;
}

sendMessageDelayed() 最终又调用了 sendMessageAtTime() :

  1. 获取当前 Handler 所在的消息队列(Handler 从持有的Looper中获取消息队列)
  2. 判断消息队列是否为空,不为空则将该消息追加到消息队列中。为空则报异常。

Handler发送消息的过程仅仅是像消息队列中插入了一条消息。MessageQueue 的 next() 就会返回一个新消息给 Looper,Looper收到新消息就开始处理(交给Handler处理),最终调用 Handler 的 dispatchMessage(Message msg)

    public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
    handleCallback(msg);} else {
    if (mCallback != null) {
    if (mCallback.handleMessage(msg)) {
    //使用的post:Runnable即为mCallback。handleMessage调用了Runnable的run()return;}}handleMessage(msg);//否则调用的是sendMessage().}}

5 主线程的消息循环

主线程即UI线程,就是 ActivityThread , ActivityThread被创建时就会初始化Looper,这也是主线程默认可以使用 Handler 的原因。

Android应用程序的入口实际上是 ActivityThread.main() :首先会创建 Application 和默认启动的Activity,并将它们关联在一起。该应用的UI线程的消息循环也是在这里创建的。

public ststic void main(String[] args){
    //...Process.setArgV0("pre-initialized");//1.创建消息循环Looper,就是UI线程的消息队列Looper.prepareMainLooper();//启动ActivityThread,这里最终会启动应用程序ActivityThread thread = new ActivityThread();thread.attach(false);AsyncTask.init();//2.执行消息循环Looper.loop();
}

此后Looper会一直从消息队列中取消息,然后处理消息。用户或系统通过Handler不断往消息队列中添加消息,这些消息不断地被取出、处理、回收,使得应用迅速地运转起来。

主线程的消息循环开始后,ActivityThread 还需要一个 Handler 来和消息队列进行交互,这个就是 ActivityThread.H ,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程。

private class H extends Handler {
     
//启动Activity 
public static final int LAUNCH_ACTIVITY = 100; 
//暂停Activity 
public static final int PAUSE_ACTIVITY = 101; 
public static final int PAUSE_ACTIVITY_FINISHING= 102; 
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
//...
}

ActivityThread 通过 ApplicationThread 和 AMS 进行进程间的通信,AMS以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 中的Binder方法,然后 ApplicationThread 会向 H 发送消息,H收到消息后切换到主线程(ActivityThread)中去执行。这个过程就是主线程的消息循环模型。


6 AsyncTask

6.1 线程和线程池

线程主要分为主线程(UI线程)和子线程(工作线程),主线程主要处理和界面相关的事情,子线程主要处理一些耗时操作。

除了 Thread 以外,在 Android 中扮演线程角色:AsyncTask、IntentService,HandleThread也是一种特殊的线程。

  • AsyncTask的底层用了线程池
    • 封装了线程池和Handler
    • 作用:为了方便开发者在子线程更新UI
  • IntentService,HandleThread的底层直接用了线程
    • IntentService:是一种服务。内部采用HandleThread来执行任务,任务结束后退出。
    • HandleThread:是一种具有消息循环的线程。其内部实现为:Handle + Thread + Loop

6.2 AsyncTask 的使用

AsyncTask是一种轻量级的异步任务类,可以在线程池中执行后台任务,把执行进度和最终结果传到主线程并更新UI。(被api30弃用,直接使用线程池+Handler或者使用Kotlin的协程)

注意:只适合不太耗时的后台任务,对于特别耗时的任务还是交给线程池去处理。

AsyncTask本质上就是Handler+Thread封装。

public abstract class AsyncTask<Params, Progress, Result>//三个泛型参数
//Params:参数类型
//Progress:执行进度的类型,一般情况为Integer
//Result:返回结果的类型

4个核心方法:

protected void onPreExecute() {
    }
protected abstract Result doInBackground(Params... params);
protected void onProgressUpdate(Progress... values) {
    }
protected void onPostExecute(Result result) {
    }
  1. onPreExecute():在主线程执行,在异步任务执行前执行,做一些准备工作。
  2. doInBackground(Params… params):在线程池执行,用于执行异步任务。
  3. onProgressUpdate(Progress… values):在主线程中执行,当后台任务的执行进度发生改变时会调用此方法。
  4. onPostExecute(Result result):在主线程执行,异步任务完成后调用。

使用:

class DownloadFilesTask extends AsyncTask<URL,Integer,Long> {
    @Overrideprotected Long doInBackground(URL... urls) {
    int cnt = urls.length;long totalSize = 0;for(int i=0;i<cnt;i++){
    totalSize += DownLoader.downloadFile(urls[i]);//进度发生变化调用publishProgress(Process process)publishProgress((int) ((i/(float)cnt)*100));if(isCancelled()){
    break;}}return totalSize;}@Overrideprotected void onProgressUpdate(Integer... process) {
    setProgressPercent(process[0]);}@Overrideprotected void onPostExecute(Long result) {
    showDialog("Download"+result+" bytes");}
}

在主线程调用

new DownloadFilesTask.execute(url1,url2,url3);

6.3 AsyncTask 工作原理

AsyncTask最适合使用的场景是多线程,开始在代码中已经看到了在AsyncTask内部有自己维护的线程池,默认的是SERIAL_EXECUTOR

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
为什么要求AsyncTask在主线程加载(AsyncTask用于更新UI时)?

在执行AsyncTask构造方法时,会初始化内部handler,会判断

  • 传入的Looper为空或者传入的Looper是主线程的Looper:获取静态Handler(处于主线程的Handler)
  • 否则:创建一个传入Looper的子线程的Handler
    public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() //要求AsyncTask在主线程加载? getMainHandler(): new Handler(callbackLooper);}//mHandler初始化private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
    if (sHandler == null) {
    sHandler = new InternalHandler(Looper.getMainLooper());}return sHandler;}}//sHandlerprivate static InternalHandler sHandler;private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
    super(looper);}@SuppressWarnings({
    "unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {
    AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {
    case MESSAGE_POST_RESULT://收到任务结束:调用finish() 返回结果result.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS://收到更新进度:调用onProgressUpdate() 更新进度result.mTask.onProgressUpdate(result.mData);break;}}}

InternalHandler用于将执行环境从线程池切换到主线程。

//构造方法

public AsyncTask() {
    this((Looper) null);
}public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
}public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() //要求AsyncTask在主线程加载? getMainHandler(): new Handler(callbackLooper);mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
    mTaskInvoked.set(true);Result result = null;try {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams);//执行耗时操作Binder.flushPendingCommands();} catch (Throwable tr) {
    mCancelled.set(true);throw tr;} finally {
    postResult(result);//结果传给内部的Handler(跳转主线程返回结果)}return result;}};mFuture = new FutureTask<Result>(mWorker) {
    @Overrideprotected void done() {
    try {
    postResultIfNotInvoked(get());} catch (InterruptedException e) {
    android.util.Log.w(LOG_TAG, e);} catch (ExecutionException e) {
    throw new RuntimeException("An error occurred while executing doInBackground()",e.getCause());} catch (CancellationException e) {
    postResultIfNotInvoked(null);}}};
}//postResult:结果传给内部的Handler(跳转主线程返回结果)private Result postResult(Result result) {
    // getHandler()返回的是InternalHandler实例,一个主线程HandlerMessage message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();//Handler发送消息return result;}//obtainMessage((what)MESSAGE_POST_RESULT,(Object)new AsyncTaskResult<Result>(this, result))public final Message obtainMessage(int what, @Nullable Object obj) {
    return Message.obtain(this, what, obj);}//AsyncTaskResultprivate static class AsyncTaskResult<Data> {
    final AsyncTask mTask;final Data[] mData;AsyncTaskResult(AsyncTask task, Data... data) {
    mTask = task;mData = data;}}

初始化两个对象:mWorker、mFuture。mWorker是一个Callable对象,作为mFuture的构建参数。mFuture是一个FutureTask对象,并在初始化mFuture的时候将mWorker作为参数传入。

public class FutureTask<V> implements RunnableFuture<V> {
    //...public FutureTask(Callable<V> callable) {
    if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}public void run() {
    if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return;try {
    Callable<V> c = callable;if (c != null && state == NEW) {
    V result;boolean ran;try {
    //然后调用线程池的execute()方法(执行mFuture的run方法)。//执行具体的耗时任务,即开头构造函数中mWorker中call()方法的内容。//先执行完doInBackground()方法,又执行postResult()方法result = c.call();ran = true;} catch (Throwable ex) {
    result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {
    runner = null;int s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}//...
}

execute():

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
    if (mStatus != Status.PENDING) {
    switch (mStatus) {
    case RUNNING:throw new IllegalStateException("Cannot execute task:"+ " the task is already running.");case FINISHED:throw new IllegalStateException("Cannot execute task:"+ " the task has already been executed "+ "(a task can be executed only once)");}}mStatus = Status.RUNNING;onPreExecute();mWorker.mParams = params;exec.execute(mFuture);//把mFuture加载到串行线程池return this;}

exec也就是sDefaultExecutor 是一个串行的线程池,一个进程中的所有的 AsyncTask 全部在这个串行的线程池中排队执行。具体是SerialExecutor类

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();Runnable mActive;public synchronized void execute(final Runnable r) {
    mTasks.offer(new Runnable() {
    public void run() {
    try {
    r.run();//1.加入新任务,即mFuture} finally {
    scheduleNext();//调用THREAD_POOL_EXECUTOR执行队列头部的任务}}});//判断是否有正在执行的任务,没有的话,就执行下一个任务if (mActive == null) {
    scheduleNext();}}protected synchronized void scheduleNext() {
    // 从任务队列里获取一个任务,并放到线程池中去执行if ((mActive = mTasks.poll()) != null) {
    THREAD_POOL_EXECUTOR.execute(mActive);}}}

SerialExecutor 内部维持了一个队列,通过锁使得该队列保证AsyncTask中的任务是串行执行的,即多个任务需要一个个加到该队列中,然后执行完队列头部的再执行下一个,以此类推。

AsyncTask维护了两个线程池(SerialExecutor、THREAD_POOL_EXECUTOR):

  • SerialExecutor:用于任务的排队
  • THREAD_POOL_EXECUTOR:用于真正执行任务

THREAD_POOL_EXECUTOR:实际是个线程池,开启了一定数量的核心线程和工作线程。

    public static final Executor THREAD_POOL_EXECUTOR;static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), sThreadFactory);threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);THREAD_POOL_EXECUTOR = threadPoolExecutor;}

然后调用线程池的execute()方法。执行具体的耗时任务,即开头构造函数中mWorker中call()方法的内容。先执行完doInBackground()方法,又执行postResult()方法,下面看该方法的具体内容:

//postResult:结果传给内部的Handler(跳转主线程返回结果)
private Result postResult(Result result) {
    // getHandler()返回的是InternalHandler实例,一个主线程HandlerMessage message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}

该方法向Handler对象发送了一个消息,下面具体看AsyncTask中实例化的Hanlder对象的源码:

private static class InternalHandler extends Handler {
    public InternalHandler() {
    super(Looper.getMainLooper());}@SuppressWarnings({
    "unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {
    AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {
    case MESSAGE_POST_RESULT:// 调用finish()result.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS://更新进度result.mTask.onProgressUpdate(result.mData);break;}}}

在InternalHandler 中,如果收到的消息是MESSAGE_POST_RESULT,即执行完了doInBackground()方法并传递结果,那么就调用finish()方法。

private void finish(Result result) {
    if (isCancelled()) {
    onCancelled(result);} else {
    onPostExecute(result);}mStatus = Status.FINISHED;}

如果任务已经取消了,回调onCancelled()方法,否则回调 onPostExecute()方法。

AsyncTask的默认线程池(SerialExecutor)是串行的。若想使用并行执行任务,可使用executeOnExecutor()传入自定义的线程池来执行任务。

在executeOnExecutor中可以传入自己自定义的线程池:

//跟默认一样的按顺序执行
asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor());
//无限制的Executor
asyncTask.executeOnExecutor(Executors.newCachedThreadPool());
//同时执行数目为10的Executor
asyncTask.executeOnExecutor(Executors.newFixedThreadPool(10));

AsyncTask 其他属性:

//获取CPU数目
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心工作线程(同时执行的线程数)
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//线程池允许的最大线程数目
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空闲线程超时时间(单位为S)
private static final int KEEP_ALIVE = 1;
//线程工厂
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);public Thread newThread(Runnable r) {
    return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());}
};
//阻塞队列,用来保存待执行的任务(最高128个)
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);

6.4 AsyncTask 使用不当的后果

  1. 生命周期

AsyncTask不与任何组件绑定生命周期,所以在Activity/Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);

  1. 内存泄漏

如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

  1. 结果丢失

屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

  相关解决方案