AsyncTask是Android中用来执行异步任务的类,底层封装了线程池和Handler。虽然现在很少使用它,它的缺点也是很明显的,比如会导致严重的内存泄漏等。尽管如此,抱着学习的态度,它的源码还是值得分析的。首先还是略微就AsyncTask的基本使用来进行一些说明:
- doInBackground(Params... params):在子线程中执行(实际上是在AsyncTask底层维护的线程池中执行),参数params表示传入的参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会导致onProgressUpdate方法的执行,另外此方法还有一个任务就是需要返回结果给onPostExecute()。
- 还有几个重要方法:
onPreExecute():在主线程中执行,一般用于做一些准备工作
onPostExecute():在主线程中执行,当异步任务执行结束之后此方法得到调用。
onProgressUpdate():运行在主线程中,用来更新任务的进度;
publishProgress():在doInBackground中调用,通知进度更新,从而导致onProgressUpdate()方法得到执行;
execute(Params... params):用来开始异步任务;
onCanceled():运行在主线程中,当异步任务被取消时,此方法会被调用,而onPostExecute方法不会被回调。
Params:表示传入参数的类型,也就是execute、doInBackgroud方法的参数类型,一般为String类型,传入所需的url。
Progress:表示进度的类型,一般是Integer。
Result:表示返回结果的类型,是doInBackground方法的返回类型,也是onPostExecute方法的参数类型。
下面给出一般使用的示例代码:
public class DownloadTask extends AsyncTask{
protected void onPreExecute(){
showDialog();
}
protected Integer doInBackground(String... params){
//联网下载,在子线程中
}
protected void onPostExecute(Integer status){
mDialog.dismiss();
}
protected void onProgressUpdate(Integer... progress){
mProgressBar.setProgress(progress[0]);
}
}
然后调用AsyncTask的execute(“http://www.baidu.com”)方法。这样就可以实现具体异步功能了。下面才是重点,才更有价值,进行源码分析(版本是25)。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
直接调executeOnExecutor方法
public final AsyncTask 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);
return this;
}
首先根据状态来进行判断,如果已经在运行或者已经结束则直接抛出异常,不再往下进行。然后把mStatus状态置为运行状态。接着,我们会看到一个熟悉的方法->onPreExecute(),这个时候程序还是运行在主线程(前提是execute在主线程中调用的,并且官方文档也指明了这一点),正好印证了前面的结论:此方法是在异步任务开始前得到执行的,并且运行在主线程中。
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
注意这个sDefaultExecutor是static的
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
到这里,我们的分析流程就到了SerialExecutor这个类的execute()方法中。实际上就三个部分:
第一次进来,mActive为null,则会调用scheduleNext方法。而scheduleNext方法呢?就是从集合中取出Runnable对象传入线程池执行。
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
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;
}
对线程池不理解也没关系,可以将其看做是new Thread(new Runnable{})形式即可。换句话说,也就是从现在开始,程序的执行已经放在了子线程中。那到底在子线程中干了什么呢?我们来看前面创建的匿名内部类的run方法:直接调用传入的Runnable的run方法,执行完后接着调用scheduleNext方法。这样,我们就可以不断从mTask集合中不断取出异步任务,然后去执行。实现了一种类似递归的机制(和Handler在handleMessage方法中再次发消息的机制类似)。实际上,我们从这里也可看出:如果我们有多个异步任务,那么他们实际上是串行去处理的,并非并行(因为sDefaultExecutor是静态的)。 现在,我们就来看看传给SerialExecutor的execute方法的Runnable的run方法中到底干了什么(因为前面提到的匿名Runnable对象并没干实质性的工作,它的作用仅仅是负责当一个异步任务执行完成后,然后再去取其它任务让其得以执行。仔细想想,这个地方用到了代理模式)。
mWorker.mParams = params;
exec.execute(mFuture);
private final FutureTask mFuture;
那么mFuture在哪里初始化的呢?我们来看构造器。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
* */
public AsyncTask() {
mWorker = new WorkerRunnable() {
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;
}
};
mFuture = new FutureTask(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);
}
}
};
}
这个FutureTask实现了RunnableFuture接口,而RunnableFuture又是继承自Runnable接口。也就是说实际上我们就只需要看FutureTask的run方法是如何实现的就行了。
public void run() {
if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
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);
}
}
重点看两行:
Callable c = callable;
result = c.call();
调了callable的call方法,那么这个callable引用到底指向谁?我们来看FutureTask的构造器:
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
从构造器中传入的。
mFuture = new FutureTask(mWorker)
mWorker = new WorkerRunnable() {
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;
}
};
那现在我们就明白了,实质性工作是在这里的call方法中进行的:
调用了postResult()方法
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
postResult就是在构造Message,然后通过Handler发送出去。分析也就到了Handler的实现上,阅读getHandler()的源码:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
根据消息的类型,执行不同的操作。在这里我们看到了熟悉的onProgressUpdate()方法得到了调用,还有几个熟悉的方法不是那么明显,就是这里的finish方法,即AysncTask的finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在这里我们看到了或者onPostExecute()或者onCancelled()得到了调用。
还有一个问题,咱们可以去思考一下,这个Handler最终是切换到了主线程去运行了吗?是,何以见得?当然是此处Handler的构造器
public InternalHandler() {
super(Looper.getMainLooper());
}
InternalHandler的Looper是主线程的Looper。如果还不理解的话,就需要看Handler源码分析了。Handler源码分析。
首先,AsyncTask在其构造器中初始化了两个域,一个是WorkRunnable的子类,另一个是FutureTask的子类。其次,我们的分析要从execute开始: AsyncTask.execute()-> AsycnTask.executeOnExecutor(),然后根据当前AsyncTask的状态来区分,不是PENDING状态的都抛异常。然后改状态为运行,记录传入execute的参数到mWorker,同时回调onPreExecute()方法,最后启动线程池执行任务,这个线程池是串行执行任务的。在线程池执行任务过程中,会调用前面在构造器中初始化的FutureTask的run方法,在run方法中又会WorkRunnable的call方法,call方法里会回调doInBackground,最终执行FutureTask的done方法,在此方法中会通过Handler转换到主线程然后回调onPostExecute()方法。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue)
a) 核心线程数 = CPU核心数 + 1
b) 线程池最大线程数 = CPU核心数 * 2 + 1
c) 核心线程无超时机制,非核心线程在闲置的超时时间为1秒
d) 任务队列的容量为128
FixedThreadPool:线程数量固定的线程池。当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。本质:只有核心线程,并且核心线程没有超时机制,任务队列也没有大小限制
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
CachedThreadPool:线程数量不定,只有非核心线程,最大线程数为Integer.MAX_VALUE。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理任务,否则就会利用空闲的线程来处理新任务。空闲线程有超时机制,时长为60秒钟,超过60秒钟闲置线程就会被回收。任务队列为空集合。适合执行大量的耗时比较少的任务。OkHttp的Dispatcher中使用的就是类似线程池(2017.12.26日添加)。
(姗姗KFC) ------即ssfc,每句首字母,我有个女同学叫姗姗
Single专一爱一人
S原配妾即丢 -----原配:比喻成核心线程,妾比喻非核心线程
F妻定不要妾,来者不拒 ---备胎是指任务队列
C与妾情60秒,无备胎