菜鸟看源码之AsyncTask

本文深入剖析了Android中AsyncTask的源码,详细解释了其工作原理,包括构造函数、execute方法、Handler机制、线程池使用及任务执行流程。

首先扯点别的:今天是第二天上班,看了看日历已经是2月23号了,2018年还剩9个多月。真是感觉人生如白驹过隙啊。今年自己竟然不知不觉已经26周岁了,趁着还算比较年轻(再过个3,4年这话就不好说了),努力奋斗!

今天梳理一下AsyncTask的源码

基于源码8.0

这部分文字叙述摘抄自郭霖老师的博客 Android AsyncTask完全解析,带你从源码的角度彻底理解

先看基本的使用方法:由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:

  1. Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
  2. Progress:后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
  3. Result:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

继承AsyncTask通常需要重写下面几个方法

  1. onPreExecute():这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
  2. doInBackground(Params…):这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress…)方法来完成。
  3. onProgressUpdate(Progress…):当在后台任务中调用了publishProgress(Progress…)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
  4. onPostExecute(Result):当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

以下载一个文件为例

新建DownloadTask类继承AsyncTask
    static class DownloadTask extends AsyncTask<String, Integer, Boolean> {

        private final String TAG = getClass().getName();

        @Override
        protected void onPreExecute() {
            Log.d(TAG, "onPreExecute: showDialog");
        }

        @Override
        protected Boolean doInBackground(String... strings) {
            String url = strings[0];
            try {
                while (true) {
                    int percent = doDownload(url);
                    //发布进度
                    publishProgress(percent);
                    if (percent >= 100) {
                        //下载完成
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            int progress = values[0];
            //设置进度
            Log.d(TAG, "onProgressUpdate: progress=" + progress);
        }

        @Override
        protected void onPostExecute(Boolean success) {
            Log.d(TAG, "onPostExecute: dismissDialog");
            if (success) {
                Log.e(TAG, "success");
            } else {
                Log.e(TAG, "failed");
            }
        }

        //模拟下载的方法
        private int doDownload(String url) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        }
    }
使用
private DownloadTask downloadTask;
downloadTask = new DownloadTask();       
downloadTask.execute("http://blog.youkuaiyun.com/u011240877/article/details/72905633");

如果要取消正在执行的任务

if (!downloadTask.isCancelled()) {
    downloadTask.cancel(true);
}

源码分析

首先先看一下AsyncTask的构造函数,必须在主线程调用

public AsyncTask() {
    this((Looper) null); 
}
public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
		//注释1处
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
		//注释2处
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };
		//注释3处
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected 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);
                }
            }
        };
    }

在注释1处,为mHandler赋值,mHandler是一个Handler类型的对象。因为我们传入的Looper对象是null,所以会调用getMainHandler方法为mHandler赋值。

private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            //传入的Looper对象是主线程的Looper对象
            sHandler = new InternalHandler(Looper.getMainLooper());
        }
        return sHandler;
    }
}

方法返回的是一个InternalHandler对象。并且返回的InternalHandler对象是和主线程的Looper对象关联的。这也是为什么onProgressUpdate方法和onPostExecute方法在主线程执行的原因。

在注释2处为mWorker赋值,mWorker是一个WorkerRunnable对象。WorkerRunnable是AsyncTask的静态内部类,它是一个抽象类。

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    //保存要执行的任务的参数
    Params[] mParams;
}

注意WorkerRunnable是实现了Callable接口的。当WorkerRunnable被执行的时候,它的call方法会被调用并返回执行结果。

在注释3处使用mWorker对象为mFuture赋值,mFuture是一个FutureTask对象。当 FutureTask 运行的时候会执行我们传入的 mWorker 对象的 call 方法。

 public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    //开始FutureTask的状态是NEW
    this.state = NEW;       
}

好了,构造函数先看到这里,接下来我们看一看AsyncTask的 execute方法。

//execute方法要在主线程调用
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
     //内部调用executeOnExecutor方法
    return executeOnExecutor(sDefaultExecutor, params);
}

调用executeOnExecutor方法

@MainThread
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)");
                }
            }
    		//AsyncTask的任务状态初始化为RUNNING
            mStatus = Status.RUNNING;
            
            //注释1处
            onPreExecute();
    		//注释2处
            mWorker.mParams = params;
            //注释3处执行任务
            exec.execute(mFuture);
    		//返回AsyncTask对象本身用于取消任务
            return this;
        }    
    

在上面的代码中可以看到,注释1处最先执行的是 onPreExecute 方法。
然后在注释2处为mWorker的mParams赋值。

注释3处,这里要注意一下,开始执行任务 exec.execute(mFuture);

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
}

当我们调用AsyncTask的execute(Params... params)方法的时候,内部会调用executeOnExecutor(Executor exec, Params... params)方法,传入的exec参数就是AsyncTask默认的 sDefaultExecutor

我们也可以直接调用AsyncTask的executeOnExecutor(Executor exec, Params... params)方法并传入我们自定义的一个Executor。就像下面这样:

Executor exec = new ThreadPoolExecutor(15, 200, 10,
		TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
//传入自定义的Executor
new DownloadTask().executeOnExecutor(exec, "downloadUrl");

本篇文章只讨论使用AsyncTask默认执行器的情况。那么接下来我们看看AsyncTask的默认执行器sDefaultExecutor是何方神圣。

//注释1处
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//按顺序线性执行任务的执行器
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

注释1处注意一下,sDefaultExecutor是一个静态变量,也就是说应用中的所有AsyncTask实例,都会共用这一个Executor。

SerialExecutor类:作用是为了保证任务是按顺序执行的。

 private static class SerialExecutor implements Executor {
     final ArrayDeque < Runnable > mTasks = new ArrayDeque < Runnable > ();
     Runnable mActive;
     public synchronized void execute(final Runnable r) {
         //注释1处将任务加入到mTasks
         mTasks.offer(new Runnable() {
             public void run() {
                 try {
                     r.run();
                 } finally {
                     //注释3处
                     scheduleNext();
                 }
             }
         });
         //注释2处
         if(mActive == null) {
             //开始执行任务
             scheduleNext();
         }
     }
     protected synchronized void scheduleNext() {
         if((mActive = mTasks.poll()) != null) {
             //注释4处
             THREAD_POOL_EXECUTOR.execute(mActive);
         }
     }
 }

当我们调用 exec.execute(mFuture);的时候:

首先在注释1处,处会把传入的mFuture加入到SerialExecutor的任务队列中。

然后注释2处,如果SerialExecutor中没有正在执行的任务,就调用scheduleNext方法来从任务队列中取出一个任务,如果任务不为null,就执行该任务。

注释3处,当一个任务执行完毕以后,然后再调用scheduleNext方法执行下一个任务,从这里我们可以看出AsyncTask默认是顺序执行任务的,每次只有一个任务被执行。

注释4处,使用THREAD_POOL_EXECUTOR来执行任务.。这个THREAD_POOL_EXECUTOR是个什么东东,了解一下。

AsyncTask类部分代码

//核心线程池数量
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大线程池的数量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//非核心线程池存活时间
private static final int KEEP_ALIVE_SECONDS = 30;
//线程池的任务队列,限制长度为128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        //允许核心线程超时
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

好了,现在我们知道了THREAD_POOL_EXECUTOR就是一个线程池,负责为我们创建线程来执行任务。当我们调用 THREAD_POOL_EXECUTOR.execute(mActive);时候,会从线程池中取出一个线程执行mActive的run方法。

SerialExecutor的execute方法

public synchronized void execute(final Runnable r) {
    mTasks.offer(new Runnable() {
        public void run() {
            try {
                //调用传入的Runnable对象的run方法
                r.run();
            } finally {
                scheduleNext();
            }
        }
    });
    if(mActive == null) {
        scheduleNext();
    }
}

当mActive的run方法执行的时候,会调用传入的Runnable对象的run方法。在上面的分析中可以知道我们传入的Runnable对象r就是mFuture,是一个FutureTask对象。

接下来看一下mFuture的run方法

public void run() {
    //...
    try {
        //这个callable就是我们传入的mWorker对象。
        Callable < V > c = callable;
        if(c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                //注释1处
                result = c.call();
                ran = true;
            } catch(Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            //注释2处
            if(ran) set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if(s >= INTERRUPTING) handlePossibleCancellationInterrupt(s);
    }
}

在mFuture的run方法的注释1处调用了我们传入的mWorker对象的call方法。再贴一下mWorker对象赋值的代码。

mWorker = new WorkerRunnable < Params, Result > () {
    public Result call() throws Exception {
        //注意,这里我们把mTaskInvoked设为了true
        mTaskInvoked.set(true);
        Result result = null;
        try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            //注释1处
            result = doInBackground(mParams);
            Binder.flushPendingCommands();
        } catch(Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            //注释2处
            postResult(result);
        }
        //注释3处
        return result;
    }
};

在mWorker的call方法中首先把mTaskInvoked设为了true,然后在注释1处,首先调用了doInBackground开始执行任务。然后在注释2处把执行结果post了出去。我们看一下AsyncTask的postResult方法。

private Result postResult(Result result) {
    //发送MESSAGE_POST_RESULT类型的消息
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, 
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

在postResult方法内部先调用getHandler获取mHandler对象,然后使用mHandler发送MESSAGE_POST_RESULT类型的消息。在上文的分析中我们知道mHandler是一个InternalHandler对象,我们看一下InternalHandler这个类。

private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // 调用AsyncTask的finish方法。
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

在InternalHandler的handleMessage方法中,如果发送的消息类型是MESSAGE_POST_RESULT的话就调用AsyncTask的finish方法。

private void finish(Result result) {
    if(isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    //将任务的状态置为FINISHED
    mStatus = Status.FINISHED;
}

在方法内部,如果任务被取消了,就调用onCancelled方法,否则就调用onPostExecute方法。最后还要把AsyncTask的状态置为FINISHED。其实到这里对用户来说,执行已经结束了。

我们回到在mWorker的call方法的注释3处,返回了执行结果。

然后继续回到接下来看一下mFuture的run方法的注释2处

if (ran)
     set(result);

FutureTask的set方法

protected void set(V v) {
    if(U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
        outcome = v;
        //将FutureTask的状态置为NORMAL
        U.putOrderedInt(this, STATE, NORMAL); // final state
        //调用finishCompletion方法
        finishCompletion();
    }
}
 private void finishCompletion() {
     //...
     //调用done方法
     done();
     //将callable置为null
     callable = null;
 }

我们看到在finishCompletion方法中调用了done方法,我们在初始化mFuture的时候覆盖了done方法,我们看一下。

 mFuture = new FutureTask <Result>(mWorker){
 
    @Override
    protected void done() {
        try {
            //注释1处
            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);
        }
    }
};

在上面代码中的注释1处首先调用了FutureTask的get方法获取执行结果,然后调用postResultIfNotInvoked方法。

AsyncTask的postResultIfNotInvoked方法

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if(!wasTaskInvoked) {
        postResult(result);
    }
}

因为在mWorker的call方法中我们把mTaskInvoked设为了true,所以这里是不会执行的。到此整个分析过程就结束了。

总结:

  • AsyncTask内部还是通过Handler机制来实现后台线程和主线程间通信。当需要发布任务的执行进度和返回执行结果的时候,就是用一个主线程的Handler发送消息,然后在主线程进行UI改变。
  • AsyncTask 内部使用一个SerialExecutor 执行器来保证线性执行提交的任务。
  • 使用 ThreadPoolExecutor 来创建线程执行任务。

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值