在学习Android的时候,我们用到比较多的异步处理的类大概就是AsyncTask,但是很多时候只知道调用,却不知道思考一些东西。
本文就简单的总结和分析了一些AsyncTask的知识。
一、AsyncTask使用
直接继承AsyncTask,它一共有3个泛型参数Params, Progress, Result.
public abstract class AsyncTask<Params, Progress, Result>
- Params表示AsyncTask执行任务的参数的类型(传入的参数的类型,在doInBackground用到的,使用execute方法中传入)
- Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型(在onProgressUpdate中用到,使用publicProgress中传入)
- Result表示任务全部完成后所返回的数据类型(doInBackground方法的返回值)
必须实现的方法有一个:
protected abstract Result doInBackground(Params... params);
这个方法是在异步线程中执行的,我们主要操作和实现的就是这个方法。
有3个方法需要熟悉:
#异步执行之前也就是doInBackground之前执行
protected void onPreExecute()
#异步执行之后也就是doInBackground之后执行
protected void onPostExecute(Result result)
#执行过程中执行
protected void onProgressUpdate(Progress... values)
这3个方法都是在UI线程中,所以可以直接更新UI。
执行的方法有两个:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
execute方法,每次只能执行一个线程,不支持并发。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
executeOnExecutor可以添加自己的线程池,是可以支持并发的。
AsyncTask使用的注意事项:
-
AsyncTask的实例必须在主线程中创建。
-
AsyncTask的execute方法必须在主线程中调用。
-
onPreExecute()、onPostExecute(Result),、doInBackground(Params…) 和 onProgressUpdate(Progress…)这四个方法都是回调方法,Android会自动调用,我们不要自己调用。
-
对于一个AsyncTack的实例,只能执行一次execute,在该实例上第二次执行execute时就会抛出异常。
前两条基本是一个意思,就是使用AsyncTask的时候在UI线程中创建/执行。4个主要的方法不能在外部去调用,一个AsyncTask执行一次。
二、源码分析
AsyncTask主要是通过线程池+handler来实现。
线程池:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
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;
/**
* 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;
}
使用ThreadPoolExecutor创建一个线程池,这线程池的核心线程是动态的,根据cpu的数量来定(2-4)个,在4.4之前的核心线程数是5。
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();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
把Runnable放入双端队列末尾,交给线程池去处理。(java.util.ArrayDeque.offer(E e) 方法将指定元素E在此deque队列的末尾。
java.util.ArrayDeque.poll() 检索并移除此queue队列表示的队列的头部,如果此queue队列为空,返回null)
具体的线程:
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;
}
};
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+Callable实现了异步线程,WorkerRunnable 实现了Callable接口。
(实现多线程的方式有几种?可能现在需要多记一种Callable)
主要Handler:
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:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
在实例化AsyncTask的时候会去准备好线程池、线程和handler,在execute执行的时候把线程扔到线程池中执行,执行中可以发送数据给handler(publishProgress),结束后发消息给handler(postResult)。
根据源代码可以总结出:
- execute方法会调用executeOnExecutor方法,使用的线程池还是默认的
- executeOnExecutor和execute在UI线程执行,那么里面调用的所有方法也是在UI线程中,所以onPreExecute()方法在UI线程中
- handler使用的是UI线程的looper = Looper.getMainLooper(),那么Handler的handleMessage方法在UI线程中,所以onPostExecute和onProgressUpdate在UI线程中。