首先看一下AsyncTask在Android中的一个简单应用:
package com.example.zhy_asynctask_demo01;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = "MainActivity";
private ProgressDialog mDialog;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(false);
new MyAsyncTask().execute();
}
private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
{
@Override
protected void onPreExecute()
{
mDialog.show();
Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
}
@Override
protected Void doInBackground(Void... params)
{
// 模拟数据的加载,耗时的任务
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(80);
} catch (InterruptedException e)
{
e.printStackTrace();
}
publishProgress(i);
}
Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
return null;
}
@Override
protected void onProgressUpdate(Integer... values)
{
mDialog.setProgress(values[0]);
Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
}
@Override
protected void onPostExecute(Void result)
{
// 进行数据加载完成后的UI操作
mDialog.dismiss();
mTextView.setText("LOAD DATA SUCCESS ");
Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
}
}
}
在这个简单的Demo中我们可以看到 AsyncTask的入口在:
new MyAsyncTask().execute();
进入到源码中我们看下execute()方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, 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;
}
方法中根据一个枚举来判定AsyncTask的当前的状态:
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
- PENDING:还未执行过executed
- RUNNING:正在执行过程中
- FINISHED:已经结束
在executeOnExecutor中每个异步任务在完成前只能执行一次,通过上述的枚举类型中的状态实现,随后调用的是onPreExecute()方法:
protected void onPreExecute() {
}
这里还是在主线程中,我们可以重写这个方法,做一些开始异步操作前的一些准备动作。
执行完成后:
mWorker.mParams = params;
在Asytask中有两个重要的成员变量:
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
我们可以将这里的mWorker 视为一个Runable接口 这里将参数Parameter 传入到mWorker 中
接下来执行:
exec.execute(mFuture);
我们研究下这里的exec 变量:
它的传入参数是一个成员变量: sDefaultExecutor 来看下如何定义的:
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);
}
}
}
最终先开始调用的excute方法就是执行这个内部类中的excute方法:
这个方法同时也是AsyTask的精髓:
在内部类中有一个成员变量:
final ArrayDeque<Runnable> mTasks
我们介绍下这个:
1)ArrayDeque有两个类属性,head和tail,两个指针。
2)ArrayDeque通过一个数组作为载体,其中的数组元素在add等方法执行时不移动,发生变化的只是head和tail指针,而且指针是循环变化,数组容量不限制。
3)offer方法和add方法都是通过其中的addLast方法实现,每添加一个元素,就把元素加到数组的尾部,此时,head指针没有变化,而tail指针加一,因为指针是循环加的,所以当tail追上head((this.tail = this.tail + 1 & this.elements.length - 1) == this.head)时,数组容量翻一倍,继续执行。
4)remove方法和poll方法都是通过其中的pollFirst方法实现,每移除一个元素,该元素所在位置变成null,此时,tail指针没有变化,而head指针加一,当数组中没有数据时,返回null。
5)因为ArrayDeque不是线程安全的,所以,用作堆栈时快于 Stack,在用作队列时快于 LinkedList。
其实说明白了它就是一个队列,里面的offer 方法就是将请求缓存起来,poll方法用来获取一个请求,我们知道在之前的版本中AsyTask被人诟病的就是当请求数超过128后 会抛出异常,但是在新版本的AsyTask中我们用队列将请求缓存后便不存在这种风险,实际上最终excute方法会调用到的方法是 mFuture中的run方法:
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
方法中我们可以看到最终是调用到的callable 的call方法这里的callable就是两个重要的成员变量的第二个:mWorker中的call:
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
这里调用到了doInBackground(mParams) 进行耗时操作
其实总结起来AsyTask就是线程池和Handler的一个封装