当用户点击某个app,Android系统会启动一个进程,该进程包含一个Thread,称为UI 线程或主线程,主线程中有很多需要处理的事件,如系统事件处理,用户输入事件处理,UI绘制,Service,Alarm等等,而默认我们自己功能的处理逻辑也是运行在主线程的,但是如果是比较耗时的计算操作,比如网络请求或是数据读取等也在主线程执行,我们可能会感觉到明显的界面卡顿,卡顿一段时间后系统就会报ANR。。。
因此,为了保证APP顺畅地运行,需要另起线程来处理耗时操作,AsyncTask就是异步线程实现的方式之一。
AsyncTask是一个轻量级地可以跟UI线程进行通信的异步线程方式,适合于耗时比较短的计算操作,最多是只有几秒钟的耗时操作。下面简单介绍下:
AsyncTask的使用
AyncTask操作一共分为四步,顺序执行:
onPreExecute
,在后台任务执行之前调用,运行在UI线程,一般是后台任务执行前的预备工作,比如弹后台任务执行的进度条提示给用户;doInBackground
,运行在后台线程,在后台执行比较耗时的计算操作;这一步产生的计算结果可推送给onPostExecute
;并且也可以通过使用publishProgress
将任务执行的进度推送给onProgressUpdate
;此方法必须实现onProgressUpdate
, 运行在UI线程,调用publishProgress
后,此接口就会被回调到;用于展示后台计算任务的进度情况;如果任务被取消的话,此接口也不会再收到回调;onPostExecute
, 运行在主线程,doInBackground
后台任务执行结束,就会调用到此接口,后台计算结果也会传递到这个接口的参数中;
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
注: AsyncTask是一个抽象类,你必须实现执行后台任务的抽象接口doInBackground
,
AsyncTask任务的取消
一个AsyncTask任务在任何时候都可以通过调用cancel(boolean)
来取消;
- 调用了
cancel(boolean)
,再调用isCancelled()
会始终返回true; - 调用了
cancel(boolean)
,doInBackground
执行结束就不会再回调到onPostExecute
里,而是回调到onCancelled(Object)
;
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
- 为了保证任务尽可能快地被取消,你可以在
doInBackground
中通过isCancelled()
轮询检查任务是否已经被取消,取消则可直接结束后台任务的执行
任务的执行顺序,并行,串行?
AsyncTask任务从Android3.0之后为了避免并行操作引起的应用错误,后台任务都是在同一线程中执行,如果你想要并行执行的话可以通过调用executeOnExecutor(java.util.concurrent.Executor, Object[])
来实现
@hide
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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);
}
}
};
}
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;
}
AsyncTask 内部Handler实现
AsyncTask内部实现也有用到Handler,后台线程与UI线程的通信就是通过Handler实现的,将doInBackground
执行的后台结果通过Handler post到UI线程
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;
}
}
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
为什么AsyncTask的创建和execute都要在主线程执行?
因为execute()
实现里会直接调用onPreExecute()
,这个接口定义是在主线程执行的,所以execute()
也要在主线程里调用
@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;
}
写在最后:
AsyncTask适合于耗时比较短的计算操作任务,多线程通信除了AsyncTask,还有IntentService,Handler等,稍后会一一说下自己的理解