您的位置:首页 > 移动开发 > Android开发

Android AsyncTask详解

2015-12-28 09:26 441 查看

前言

一提到多线程,我们不得不提到AsyncTask,很多Android开发人员在网络请求这块,一般会使用开源框架,比如Volley,Okhttp,retrofit等。但是有一部分人,比较忠于封装AsyncTask去实现。我们都知道AsyncTask内部是Handler实现的,今天我们就来一探究竟。

基本使用

AsyncTask使用了模板方法模式,使用AsyncTask,我们需要写一个类去继承它,然后重写它的几个方法,如下:

public class MyAsyncTask extends AsyncTask<String, Integer, String> {

@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}

@Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}

@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}


AsyncTask传入的参数分别代表:在调用excute方法传入的参数类型,onProgressUpdate方法的参数类型和doInBackground返回的参数类型。下面再说明下几个方法:

a.onPreExecute:最先执行的方法,运行在主线程,一般我们做显示Dialog等的准备工作。

b.doInBackground:在onPreExecute只后执行的方法,运行在线程池,这里主要做耗时操作,然后将结果返回。

c.onPostExecute:最后执行的方法,运行在主线程,方法参数为doInBackground返回的值。

d.onProgressUpdate:显示请求任务进度的方法,运行在主线程,需要在doInBackground调用publishProgress(values)方法。比如说下载任务进度。。。

在使用的时候就直接:

new MyAsyncTask().excute();//当然也可以传入一些参数


基本使用就差不多介绍完毕,下面我们罗列下AsyncTask需要注意的地方:

AsyncTask必须在主线程中加载。不过在android4.1以上系统自动完成了。AsyncTask必须在主线程中创建。excute方法必须在主线程中调用。

一个AsyncTask对象只能执行一次,也就是只能调用一次excute方法,否则会报异常。

Android1.6之前AsyncTask是串行执行任务。Android1.6到Android3.0是并行执行任务。Android3.0以后是串行执行任务,不过我们可以通过自定义线程池,调用executeOnExecutor()方法,将自定义的线程传入,然后并行处理。

不要显示去调用onPreExecute等方法。

源码分析

基本使用介绍完毕后,我们来看下AsyncTask的内部实现,先从我们的调用方法excute开始:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}


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;
}


这边分析的源码是android4.4,默认传入线程池是串行去处理的。代码3行开始,我们可以看到这里有个状态判断。总共有3个状态:Status.PENDING,Status.RUNNING,Status.FINISHED;执行前,执行中,执行完。代码17行我们就能看到onPreExecute()方法是最先执行的。20行exec.execute(mFuture);,线程池开始工作:

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);
}
}
}


这里出现两个线程池:SerialExecutor 和THREAD_POOL_EXECUTOR。从代码中我们可以看出:SerialExecutor主要是做任务的排队,而THREAD_POOL_EXECUTOR才是真正的做后台工作。

在AsyncTask中就初始化了两个对象mWorker和mFuture,这个在executeOnExecutor方法里就应用到。而上述代码第9行,调用mFuture.run方法,就保证了mWorker在线程池中调用call方法:

mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};


进入postResult方法:

private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}


这里就用到异步消息机制,进入handler:

private static class InternalHandler extends Handler {
@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 是一个静态Handler对象,为了能够将环境最终切换到主线程,那么InternalHandler就必须在主线程中。由于静态成员会在加载类的时候初始化,那么就变相的要求AsyncTask必须在主线程中加载了。这也印证了我们在前面提出的观点。

然后,这里对消息的类型进行了判断,如果这是一条MESSAGE_POST_RESULT消息,就会去执行finish()方法,如果这是一条MESSAGE_POST_PROGRESS消息,就会去执行onProgressUpdate()方法。进入finish():

private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}


可以看到,如果当前任务被取消掉了,就会调用onCancelled()方法,如果没有被取消,则调用onPostExecute()方法,这样当前任务的执行就全部结束了。

上述有一个消息MESSAGE_POST_PROGRESS处理,然后调用onProgressUpdate,发消息的地方,我们应该能想到是:publishProgress方法,如下:

protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}


至此,我们相信我们对于AsyncTask的工作原理及注意事项已经理解的很透彻了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息