我们都知道通过Handler可以实现异步任务,子线程通过Handler发消息给主线程,然后主线程执行相应的操作。在Android的异步任务体系中,还有一个非常重要的组件—AsyncTask。接下来我们先介绍AsyncTask的简单使用:
public class MainActivity extends AppCompatActivity {
private TextView tvText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvText = (TextView) findViewById(R.id.tv_text);
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyAsynTask().execute();
}
});
}
public class MyAsynTask extends AsyncTask<Integer,Integer,Integer> {
private static final String TAG ="MyAsynTask" ;
@Override
protected Integer doInBackground(Integer... integers) {
Log.e(TAG, "doInBackground: 正在执行异步任务..." );
return 0;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.e(TAG, "doInBackground: 执行异步任务之前..." );
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
Log.e(TAG, "doInBackground: 执行异步任务之后..." );
}
}
}
看上面的代码可以知道,这个组件使用起来很简单,自定义MyAsynTask 类并继承AsyncTask类,然后实现三个方法:doInBackground(正在执行异步任务),onPreExecute(执行异步任务之前),onPostExecute(执行异步任务之后)。然后创建MyAsynTask 对象,调用execute方法。我们先看下AsyncTask的构造方法。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @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);
}
}
};
}
构造方法主要初始化了三个成员变量。mHandler,mWorker,mFuture。分别是Handler,WorkerRunnable,FutureTask。Handler我们比较熟悉,用来在线程之间发送消息。WorkerRunnable,FutureTask两个对象比较陌生,主要是线程池相关的两个类,因为我们在这主要关注AsyncTask源码的流程,具体就不深究这两个对象。我们知道这两个类是和线程池相关的两个类即可。创建AsyncTask对象调用AsyncTask的构造方法之后,执行execute()方法,现在我们看下execute方法的实现。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute方法,使用了@MainThread注解,所以我们知道这个方法要在主线程执行。所以当我们调用execute()方法的时候,不要在子线程调用,在UI线程调用该方法。接着调用了executeOnExecutor()方法,我们看下executeOnExecutor()方法的实现。
@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;
}
这个方法首先判断当前任务的状态:
1、如果是RUNNING,则说明任务正在执行,接着抛出Cannot execute task:the task is already running.的异常
2、如果是FINISHED,则说明任务已经完成,接着抛出Cannot execute task: the task has already been executed (a task can be executed only once).的异常。任务已经完成,一个任务只能执行一次。也说明了一个AsyncTask对象只能调用一次executed 方法。
我们来试验一下:
private TextView tvText;
private AsyncTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvText = (TextView) findViewById(R.id.tv_text);
task = new MyAsynTask();
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
task.execute();
task.execute();
}
});
}
我们在一个TextView的点击事件中调用了两次execute方法,然后我们会看到接着就会抛出如下异常:
08-21 10:37:56.711 3251-3251/com.mujin.keji.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mujin.keji.myapplication, PID: 3251
java.lang.IllegalStateException: Cannot execute task: the task is already running.
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:580)
at android.os.AsyncTask.execute(AsyncTask.java:539)
at com.mujin.keji.myapplication.MainActivity$1.onClick(MainActivity.java:24)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5293)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
这也正证明了上面的结论。
我们继续回到上面的executeOnExecutor()方法,判断完任务状态之后,如果任务是第一次执行,那么就继续往下走
mStatus = Status.RUNNING;
修改任务的状态变成正在执行,当如果再次调用的时候,此时的任务状态是正在执行,那么就会抛上面的异常。继续往下走调用了onPreExecute方法,当我们点进去该方法
@MainThread
protected void onPreExecute() {
}
该方法是一个空方法,因为该方法由我们来实现。到了这里就完成了第一个回调方法onPreExecute,异步任务执行之前。接着我们继续往下走。
exec.execute(mFuture);
传入和线程池相关的对象mFuture,exec调用execute方法。从方法名我们大概可以猜到,该方法就是去执行异步任务的意思。接着我们进入execute方法。exec是一个SerialExecutor对象,我们看下SerialExecutor类的实现。
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类中,只有一个execute方法和一个Runnable集合(即任务列表)。execute方法中首先调用offer方法。我们进入offer方法
/**
* Inserts the specified element at the end of this deque.
*
* <p>This method is equivalent to {@link #offerLast}.
*
* @param e the element to add
* @return {@code true} (as specified by {@link Queue#offer})
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
return offerLast(e);
}
从注释我们可以看到Inserts the specified element at the end of this deque.,该方法的作用就是讲特定的原素插入到队尾。当然在这里的意思就是将异步任务插入到队尾。调用完offer方法之后,接着判断Runnable mActive对象是不是空的,如果是第一次执行,该对象为空,然后调用scheduleNext方法。在scheduleNext方法中
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
首先从任务列表头部取出任务赋值给mActive,并判断任务是不是空的,如果不为空,调用THREAD_POOL_EXECUTOR.execute(mActive);方法,执行异步任务。THREAD_POOL_EXECUTOR在这里就是一个线程池对象。其实就是从线程池中取出一个线程,然后执行该任务。在执行任务的过程中会回调WorkerRunnable mWorker 对象中的Result 方法(在AsyncTask构造方法中初始化了mWorker对象),然后在方法体内我们看到执行了doInBackground方法,也就是我们重写的doInBackground方法(正在执行异步任务)
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);
}
};
我们现在看下在AsyncTask构造方法中的第二个对象FutureTask 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);
}
}
};
执行完异步任务之后回调done()方法,在这方法体又调用了postResultIfNotInvoked方法,接着我们继续看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方法。在postResult方法中我们看到很熟悉的对象Message message 和getHandler()方法。取出一条消息,然后调用sendToTarget方法发送消息。我们看下getHandler()方法。通过一步步往下走发现
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内部自定义了InternalHandler 对象,当执行完异步任务之后发送消息,然后会在InternalHandler 类的handleMessage方法体内处理消息。我们重点看下finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
首先判断任务是否已经取消,如果取消了,取消当前操作。如果没有取消,则调用onPostExecute方法,也就是我们实现onPostExecute方法(异步任务执行完成)。然后修改异步任务的状态。AsyncTask三个回调方法执行完毕,整个流程也执行完了。在这里我们知道AsyncTask是通过线程池+Handler来实现异步任务的。接下来我们做个简单的小结:
1.初始化线程池相关的对象和Handler对象。
2.通过线程池执行异步任务。
3.通过Handler发送消息通知异步任务执行完毕。
网友评论