AsyncTask
AsyncTask能够更方便地在子线程中更新UI元素。
AsyncTask enables proper and easy use ofthe UI thread.
AsyncTask是Android提供的轻量级的异步类。
Android之所以有AsyncTask和Handler都是为了不阻塞ui线程,且ui的更新只能在主线程完成,因此异步处理时不可避免的。
首先我们讲下AsyncTask的使用
public abstractclass AsyncTask<Params, Progress, Result>
AsyncTask是一个抽象类,要使用AsyncyTask我们要提供三个泛型参数,并重载几个方法
AsyncTask定义了三种泛型类型 Params,Progress和Result。
•Params 启动任务执行的输入参数,比如HTTP请求的URL。
•Progress 后台任务执行的百分比。
•Result 后台执行任务最终返回的结果,比如String。
使用过AsyncTask的同学都知道我们经常使用这四个方法
onPreExecute():UI线程
后台任务执行之前调用,用来进行一些UI上的初始化操作,比如显示一个进度条对话框等。
doInBackground(Params...) (必须):后台进程
后台任务执行时,负责处理所有耗时任务。
onProgressUpdate(Progress...):UI线程
后台任务执行时,反馈后台任务的执行进度,进度条的改变。
onPostExecute(Result) (必须):UI线程
当然还有一个onCancelled();可以用来取消当前任务
后台任务执行完毕时调用,用返回数据来进行一些UI的操作,比如显示后台任务执行结果。
使用AsyncTask要注意的几点是
1. AsyncTask类必须在UI线程中加载
2. AsyncTask的实例必须在UI线程中创建
3. AsyncTask.execute()必须在UI 线程中调用
4. 不要手动调用doInBackground()上述的几个方法
5. AsyncTask.execute()只能调用一次
AsyncTask的执行过程
我们使用AsyncTask都是通过execute(params)方法,那么其实正在执行的方法是executeOnExecutor(),
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;
}
在这里面有一个status标志,如果status==Pending的才会正常进行,如果为Running或者FINISHED就会抛出异常,这也就是AsyncTask只能调用一次的原因,多次调用就会报错,在初始化之后就进入了我们的四大常用方法之一的onPreExecute()(进行UI的初始化)了,在这里面进行一些UI的初始化,当前线程依然处在UI线程,之后出现了两个对象一个是mWork,一个是mFuture,而在AsyncTask的构造函数中就做了两件事
1.初始化mwork2.初始化mFuture。
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);
}
};
首先说说这个mWork,他是WordRunnable的实例,WorkRunnable是一个抽象类,实现了Callable接口, 在初始化化他的时候就要实现call方法,在call中首先设置mTaskInvoked为true表示在调用,而call方法中就有另一个四大方法之一的doInbackground()(进行耗时操作);,并且将返回值作为参数给postResult方法,但是call()在这个时候还没有执行,只是初始化了mWork。
那么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发送信息,看到这基本就可以想到肯定在主线程(UI线程)中有一个handler,并且通过handlerMessage方法等待消息的接收,
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,这里处理了两种结果,一种是MESSAGE_POST_RESULT,如果message传的是这个标志,则意味着结束,也就是AsyncTask.this.finish();如果是MESSAGE_POST_PROGRESS,则意味着正在执行过程中,那么就出现了我们四大方法之一的onProgressUpdate()(更新UI,耗时任务的进度);
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在finish还有要一个常用的第五个方法,那就是onCanelled(),如果我们调用了cancel就会执行onCalled回调,如果没有取消即正常调用的话,那就是最后一个四大方法之一的onProgressExcute()将任务结果更新在UI上;最后将状态设置为FINISHED;
说了这么多mWork终于讲完了,那么现在看下mFuture,
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);
}
}
};
mFuture是将mwork作为参数的,并且复写了done方法
在done方法中调用了postResultIfNotInvokded(get());get()就是获取mWork中call的返回值,然后将结果作为PostResult()方法的参数使用,
但是说了这么多,mWork和mFuture都只是初始化了,还没有真正执行,
他的执行就是在
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
第四行代码。
这里就是一个SerialExcutor(串行执行)的实例exec,
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);
}
}
}
在SerialExcutor内部就是一个任务队列,以及一个execute(Runnable runnable)函数,
将runnable放入mTasks队尾,判断当前的Runnable执行实例mActive,如果为空,则调用scheduleNext,而scheduleNext则将队列头出列,如果任务不为空,交给线程池进行执行任务。
听到线程池,那有些人在想,那AsyncTask是可以通知执行好多个任务吗,也就是并行的吗?但是不是说AsyncTask是串行的吗?
其实AsyncTask是串行的,比如当前有10个任务同时执行了execute,方法,第一个任务入队,然后因为mActive目前是null则执行scheduleNext,则将任务出队并赋值给mActive,然后交给线程池去执行。然后第二个任务进来了,但是mActive此时不是null了,所以执行不了sceduleNext,所以只能等待,而真正执行下一个任务的时机是在线程池执行完第一个任务后,调用了Runnable中的finnaly方法,在这里执行了scheduleNext方法,所以虽然内部有一个线程池,但是其实调用的过程还是串行的,一个接一个,相当于单线程。
AsyncTask缺陷:
可以分为两个部分说,在3.0以前,最大支持128个线程的并发,10个任务的等待。也就是容易出现并发错误。所以138个任务可以并发执行,但是139个任务就会出错,那是因为在阻塞队列(10)中塞满时,会调用一个reject()放在,这个会拒绝执行这个任务,并且抛出异常。在3.0以后,无论有多少任务,都会在其内部单线程执行;
除了缺陷我在说说最开始说的那些AsyncTask的规则
1.AsyncTask 类必须在UI线程中被加载
因为AsyncTask有一个静态内部类InternalHandler,这里有handlerMessage方法,要处理ui更新,所以该hanlder要放在UI线程,因为是静态内部类,所以在类加载的时候就进行初始化了,所以AsyncTask得放在UI线程加载。
2.AsyncTask的实例必须在UI线程中创建
AsyncTask内部的onProgressUpdate()方法和onPostExecute()都是些更新UI的,所以都得处在UI进程,
在哪个线程中创建onPostExecute()方法就会在哪个线程中执行,所以AsyncTask的实例也必须在UI线程中创建。
3.AsyncTask.execute()必须在UI 线程中调用
AysncTask的execute()方法调用了onPreExecute()方法,该方法在task开始前在UI线程进行若干的准
备工作,所以必须处在UI线程中。
4.不要手动调用doInBackground()上述的几个方法
这几个方法都是些回调方法,只需要实现或重写即可
5.AsyncTask.execute()只能调用一次
首先,是源码在execute()中设置了Status状态,在task开始后Status就会变成RUNNING,就会抛出异常.
这也是为了避免AsyncTask并行执行,避免同一个任务同时被执行而造成混乱,因为并行模式时各线程间是无序执行的。