看多少总结都不如自己试着分析一遍,RTFSC。
AsyncTask用法
直接上官网的例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
写一个类继承AsyncTask,重写三个方法:
- doInBackground:在这里面执行耗时的异步任务
- onProgressUpdate:更新进度在这个方法里写
- onPostExecute:任务执行后的操作放这里面
此外还有两个方法可以重写:
- onPreExecute
- onCancelled
AsyncTask类指定三个泛型参数,这三个参数的用途如下:
- Params——在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
- Progress——后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
- Result——当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
启动这个任务:
new DownloadFilesTask().execute(url1, url2, url3);
源码分析
我的SDK版本时API 23,各版本的AsyncTask的具体代码可能会有出入,但基本的原理是一样的。
先看看构造器里都做了什么:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
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);
}
}
};
}
首先用匿名内部类的形式new了一个WorkerRunnable<Params, Result>实例,WorkerRunnable是实现了Callable接口的一个抽象类,Callable代码如下,包含一个带反回类型的call()方法:
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
回构造器看看匿名内部类里是如何实现call()方法的,在call()方法中将线程的优先级设置为了THREAD_PRIORITY_BACKGROUND
,官网说了:
If you don't set the thread to a lower priority this way, then the thread could still slow down your app because it operates at the same priority as the UI thread by default.
意思是如果不降低线程的优先级,那么子线程默认和UI线程优先级一样,执行起来app可能就卡了。
接下来就调用了doInBackground方法,返回一个result,这都是在子线程里的操作,那怎么把result传递给主线程呢?追进postResult看看:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
熟悉的Message出现了,还调用了sendToTarget()方法,这不就是通过Hadler传递的方式吗。再看getHandler方法返回的是静态内部类InternalHandler的实例,InternalHandler继承自Handler:
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;
}
}
}
InternalHandler构造器中拿的是主线程的looper,handleMessage是接收到不同消息进行相应的处理,finish:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
接收到finish消息后,如果调用了isCancelled就回调onCancelled方法,否则回调onPostExecute方法。如果消息的更新progress那么就回调onProgressUpdate方法。这样就把result传递给了主线程。
再回到构造器接着往下看:
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);
}
}
};
同样用匿名内部类生成一个FutureTask<Result>实例,FutureTask实现了RunnableFuture接口,RunnableFuture的源码如下,它同时继承了Runnable接口和Future接口,既可以作为Runnable的引用也可以作为Future的引用,Future接口中定义cancel方法和get方法用于取出线程的执行结果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
前面的FutureTask匿名内部类重写了done方法,调用postResultIfNotInvoked,如果之前WorkerRunnable的call方法抛异常了,则再次把result传递出去。
好了,构造器里定义好了一个实现Callable接口的WorkerRunnable实例和一个实现了Runnable接口和Future接口的FutureTask实例。
接下来看看调用execute方法后都做了什么:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
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)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
首先回调onPreExecute()方法,这还是在主线程,接下来调用传递进来的Executor实例的execute方法开始执行任务:
exec.execute(mFuture);
传进来的sDefaultExecutor是定义的静态内部类SerialExecutor的实例,去源码看到它实现的execute方法中使用一个双端队列来串行执行传进来的Runnable引用的run方法,具体引用是谁呢?看上面,是mFuture。在mFuture的run方法中会调用Callable引用的call方法,具体引用是谁呢?回AsyncTask构造器看,是mWorker。真正执行任务的是线程池THREAD_POOL_EXECUTOR。
AsyncTask默认线程池参数
把THREAD_POOL_EXECUTOR具体参数和定义也贴上:
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;
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());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到线程池的核心线程数是(CPU数+1),最大容量是(2*CPU数+1),阻塞队列容量128。记得AsyncTask中的线程池核心线程数是5啊,对吗?什么时候改的呢,这是API 23即Android 6.0,我们去历史版本看看吧,我一般在androidxref.com看各个版本的源码。
搜索之后可以得知,在Android 4.3的源码中AsyncTask的配置还是如下所示:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
核心线程数5,线程池最大容量128,阻塞队列容量10。从Android 4.4开始就变成上面看到的根据CPU数的配置了,涨了一点点知识,不能再说AsyncTask默认线程池核心线程数是5啦。
此外,我们还可以通过setDefaultExecutor来使用自定义的Executor和线程池来执行任务。
以上分析下来确实学到了不少啊。