在我们开发过程中,经常会用到异步操作来进行界面的更新,一般来说,在子线程更新UI线程有三种方式,具体可以看:https://blog.csdn.net/qq_29451649/article/details/79529441 但是我们在写一些复杂的操作时直接使用Handler会有点麻烦,下面我们学习一下AsyncTask的使用以及实现的原理吧。
首先看AsyncTask的定义,方法如下:
public abstract class AsyncTask<Params, Progress, Result> {...
可以看到AsyncTask是泛型类,它包含3个参数,其中Params是参数的类型,Progress后台任务执行的任务类型,Result是返回的结果类型。我们在创建 AsyncTask的时候后,要有以下四个核心的方法:
protected Object doInBackground(Object[] objects) {
return null;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
}
@Override
protected void onProgressUpdate(Object[] values) {
super.onProgressUpdate(values);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
其中除了doInBackground方法是在子线程中运行的,其他的都是在主线程中执行的。onPreExecute方法做的是初始化的工作,在任务执行前执行。doInBackground方法在onPreExecute方法之后之行,主要用来进行耗时操作,在我们执行的过程中可以调用publishProgress方法,将我们执行的进度传到下一个方法onProgressUpdate中(例如我们下载的操作),onPreExecute是在doInBackground执行完毕时进行的操作,在这里我们可以进行一些UI的更新等。
好了,用法什么的就不再说了,我们来看一下它到底是怎么实现这样的线程切换以及doInBackground到底是怎么执行操作的吧:
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;
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;
}
可以看到,在这个类中新建了一个sPoolWorkQueue,这是一个由链表组成的阻塞队列。然后通过这个阻塞队列创建了一个线程池threadPoolExecutor。下面看一下其他的参数:
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;
可以看到通过CPU_COUNT返回可用处理器的Java虚拟机的数量然后构建一个线程池。下面看一下doInBackground的实现:
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;
}
};
可以看到整合各WorkerRunnable实现的是会很少用到的Callable接口,在它的call方法中调用了doInBackground方法并获取到了Result。下面我们看一下AsyncTask的exexute的执行过程:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@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);//1
return this;
}
我们看到先是调用了executeOnExecutor方法,然后判断一下它的状态,如果是在运行和完成都会抛出异常。否则将状态设置为运行中,并调用onPreExecute方法,之后调用上面注释1处的方法,
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);
}
}
};
在上面我们说过,mWorker继承了Callable接口,这里的mFuture是一个FutureTask实现了Runnable和Callable两个接口,接着我们看postResultIfNotInvoked这个方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可以看到在postResult方法中创建了新的Message对象,到这里大家是不是都明白了,通过gethHandler方法得到Handler并通过这个handler发送消息
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
private Handler getHandler() {
return mHandler;
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
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;
}
}
} super(looper);
}
可以看到这个Handler和获取到的Looper对象是MainLooper。可以看到完成时会调用finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
现在可以看到在结束时调用了postExecute方法并将Result传了过去。好了,到这里大家就该明白这这整个执行过程了吧。