AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最后反饋執行的結果給UI主線程.
本文不分析AsyncTask的使用,它的使用教程網上一搜一大堆,本文主要分析它的內部邏輯和實現,它是怎么實現異步的,它是怎么處理多個任務的,是並發么??
一、線程任務的調度
在AsyncTask內部會創建一個類相關的線程池來管理要運行的任務,也就就是說當你調用了AsyncTask的execute()后,AsyncTask會把任務交給線程池,由線程池來管理創建Thread和運行Therad。
在Android4.0版本中它內部是有兩個線程池:SerialExecutor和ThreadPoolExecutor,SerialExecutor是串行的,ThreadPoolExecutor是並發的,而默認的就是SerialExecutor的,所以你一個程序中如果用了好幾個AsyncTask你就得注意了:不要忘了換成並發的線程池執行。下面演示一下,穿行的調度
public class AsyncTaskDemoActivity extends Activity {
private static int ID = 0;
private static final int TASK_COUNT = 9;
private static ExecutorService SINGLE_TASK_EXECUTOR;
private static ExecutorService LIMITED_TASK_EXECUTOR;
private static ExecutorService FULL_TASK_EXECUTOR;
static {
SINGLE_TASK_EXECUTOR = (ExecutorService) Executors.newSingleThreadExecutor();
LIMITED_TASK_EXECUTOR = (ExecutorService) Executors.newFixedThreadPool(7);
FULL_TASK_EXECUTOR = (ExecutorService) Executors.newCachedThreadPool();
};
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.asynctask_demo_activity);
String title = "AsyncTask of API " + VERSION.SDK_INT;
setTitle(title);
final ListView taskList = (ListView) findViewById(R.id.task_list);
taskList.setAdapter(new AsyncTaskAdapter(getApplication(), TASK_COUNT));
}
private class AsyncTaskAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mFactory;
private int mTaskCount;
List<SimpleAsyncTask> mTaskList;
public AsyncTaskAdapter(Context context, int taskCount) {
mContext = context;
mFactory = LayoutInflater.from(mContext);
mTaskCount = taskCount;
mTaskList = new ArrayList<SimpleAsyncTask>(taskCount);
}
@Override
public int getCount() {
return mTaskCount;
}
@Override
public Object getItem(int position) {
return mTaskList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mFactory.inflate(R.layout.asynctask_demo_item, null);
SimpleAsyncTask task = new SimpleAsyncTask((TaskItem) convertView);
/*
* It only supports five tasks at most. More tasks will be scheduled only after
* first five finish. In all, the pool size of AsyncTask is 5, at any time it only
* has 5 threads running.
*/
task.execute();
// use AsyncTask#SERIAL_EXECUTOR is the same to #execute();
// task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11)
// but different from newer version of #execute()
// task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// one by one, same to newer version of #execute()
// task.executeOnExecutor(SINGLE_TASK_EXECUTOR);
// execute tasks at some limit which can be customized
// task.executeOnExecutor(LIMITED_TASK_EXECUTOR);
// no limit to thread pool size, all tasks run simultaneously
//task.executeOnExecutor(FULL_TASK_EXECUTOR);
mTaskList.add(task);
}
return convertView;
}
}
private class SimpleAsyncTask extends AsyncTask<Void, Integer, Void> {
private TaskItem mTaskItem;
private String mName;
public SimpleAsyncTask(TaskItem item) {
mTaskItem = item;
mName = "Task #" + String.valueOf(++ID);
}
@Override
protected Void doInBackground(Void... params) {
int prog = 1;
while (prog < 101) {
SystemClock.sleep(100);
publishProgress(prog);
prog++;
}
return null;
}
@Override
protected void onPostExecute(Void result) {
}
@Override
protected void onPreExecute() {
mTaskItem.setTitle(mName);
}
@Override
protected void onProgressUpdate(Integer... values) {
mTaskItem.setProgress(values[0]);
}
}
}
class TaskItem extends LinearLayout {
private TextView mTitle;
private ProgressBar mProgress;
public TaskItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TaskItem(Context context) {
super(context);
}
public void setTitle(String title) {
if (mTitle == null) {
mTitle = (TextView) findViewById(R.id.task_name);
}
mTitle.setText(title);
}
public void setProgress(int prog) {
if (mProgress == null) {
mProgress = (ProgressBar) findViewById(R.id.task_progress);
}
mProgress.setProgress(prog);
}
}
2.你想要的並發執行
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
當然也可以換成你自己的線程池。
二、源碼分析
1.成員變量:
定義了需要用到的成員,可以根據名字就能知道干什么的
//生產線程的工廠
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//存放任務的阻塞隊列
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
/**
* 可以平行的執行任務!就是並發的
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
/**
* 線性執行的執行器
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//內部交互的handler
private static final InternalHandler sHandler = new InternalHandler();
//默認的Executor
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
定義了需要用到的成員,可以根據名字就能知道干什么的,另外注意都是static修飾的:
第二行的sThreadFactory是創建線程的;
第十行的sPoolWorkQueue阻塞隊列,存放任務的;
第十七行是 THREAD_POOL_EXECUTOR是線程池,這個是並發執行的線程池;
第26行是線性調度的線程池,SERIAL_EXECUTOR,執行完一個才會執行下一個;
第28行是一個內部封裝的Handler:InternalHandler
第30行可以看出他默認的是線性調度的線程池, Executor sDefaultExecutor = SERIAL_EXECUTOR,看到這里你應該注意一個問題,如果程序里有好多個AsyncTask,它們就是線性調度的,這肯定可你預想的不一樣,所以你別忘了換成並發的執行器。
2.內部Handler的使用:
2.1 自定義的InternalHandler(內部handler)
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
//接受message的處理,可以看到根據狀態選擇是完成了,還是更新着
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;
}
}
}
在上邊handleMessage中,根據msg進行判斷,是完成了還是在更新;
任務完成調用finish方法,在其中執行你定義的onPostExecute方法,
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
3.構造方法
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();
postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}
構造方法中其實隱藏的信息很多,WorkerRunnable和FutureTask;
其中WorkerRunnable繼承了Callable接口,應該是用於在未來某個線程的回調接口,在其中執行了postResult(doInBackground(mParams));調用doInBackground,並用postResult方法把result發送到主線程。
FutureTask你看類的介紹是說控制任務的,控制任務的開始、取消等等,在這不細究,跟本文關系不大,而且我也沒看明白。
第17行有一個方法:postResultIfNotInvoked(result);根據名字可以看出來是如果沒有調用就把結果post出去,所以他應該是處理取消的任務的。
看下postResult方法:代碼很少也很簡單,就是把msg發送給handler:
//用shandler把設置message,並發送。
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
構造方法就分析到這,下一步就是execute():
3.1 按照執行過程流程,實例化完,就可以調用execute():
//Params... 就相當於一個數組,是傳給doInBackground的參數
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;
}
代碼邏輯很清晰,沒有幾行:
20行:修改了狀態;
21行:准備工作;
24行:設置參數;
25行:線程池調用執行,注意參數是mFuture。
3.2 execute的執行邏輯
就以它定義SerialExecutor為例:
/*An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.*/
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);
}
}
}
可以看到它的方法都是用synchronized關鍵字修飾的,且在他的介紹里也說了在同一時間只有一個任務在執行。
- 在execute方法中把Future 的 run方法封裝到Runnable里,放到Task隊列中,如果mActive為空則調用scheduleNext方法執行任務;在這里還有一個細節就是執行完r.run(),還有個finally模塊調用scheduleNext 方法,所以它才會一個接一個的執行任務。
- 而在scheduleNext 中使用THREAD_POOL_EXECUTOR 執行任務。
三、AsyncTask中異步的處理邏輯
沒有忘了前邊構造方法中的postResult(doInBackground(mParams))和postResultIfNotInvoked(result);方法吧,如果忘了翻前邊去看。這兩個方法把執行成功的和失敗的任務都包含了。
所以我們可以設想一下它是怎么執行的:
1.在executeOnExecutor方法中給變量賦值
2.用執行器Executor另起線程執行任務
3.在Executor中一些復雜的邏輯,用FutureTask進行判斷任務是否被取消,如果沒有就調用回調接口call()方法,
4.在call()方法中調用了postResult(doInBackground(mParams));
5.postResult發送給主線程的Handler進行后續處理。
看的時候可以畫下圖,會很清晰,基本邏輯就這樣,好AsyncTask就分析到這,歡迎糾錯。。。
轉發請注明出處,原文地址:http://www.cnblogs.com/jycboy/p/asynctask_1.html
