編輯:關於android開發
AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最後反饋執行的結果給UI主線程.
本文不分析AsyncTask的使用,它的使用教程網上一搜一大堆,本文主要分析它的內部邏輯和實現,它是怎麼實現異步的,它是怎麼處理多個任務的,是並發麼??
在AsyncTask內部會創建一個類相關的線程池來管理要運行的任務,也就就是說當你調用了AsyncTask的execute()後,AsyncTask會把任務交給線程池,由線程池來管理創建Thread和運行Therad。
在Android4.0版本中它內部是有兩個線程池:SerialExecutor和ThreadPoolExecutor,SerialExecutor是串行的,ThreadPoolExecutor是並發的,而默認的就是SerialExecutor的,所以你一個程序中如果用了好幾個AsyncTask你就得注意了:不要忘了換成並發的線程池執行。下面演示一下,穿行的調度
1.一個簡單的例子:可以看出他是一個個執行的 代碼如下: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); } }
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
當然也可以換成你自己的線程池。
定義了需要用到的成員,可以根據名字就能知道干什麼的
//生產線程的工廠 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.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; }
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接口,應該是用於在未來某個線程的回調接口,在其中執行了ostResult(doInBackground(mParams));調用doInBackground並用postResult方法,把result發送到主線程。
FutureTask你看類的介紹是說控制任務的,控制任務的開始、取消等等,在這不細究,跟本文關系不大,而且我也沒看明白。
第17行有一個方法:postResultIfNotInvoked(result);根據名字可以看出來是如果沒有調用把把結果post出去,所以他應該是處理取消的任務的。
構造方法就分析到這,下一步就是execute():
看下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; }
//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。
就以它定義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關鍵字修飾的,而其讓他的介紹裡也說了在同一時間只有一個任務在執行。
在裡邊調用r.run()方法,執行完了在調用下一個。按先後順序每次只運行一個
沒有忘了前邊構造方法中的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
上次介紹了Android利用麥克風采集並顯示模擬信號,這種采集手段適用於無IO控制、單純讀取信號的
android 自學日記(一) android 自學日記(一) 說起日記,記憶還是小學時候學校裡的作業,只記得當時通篇都是流水賬,例如“幾點起床,去哪裡玩了,干了啥
對於任何軟件來說,美觀的界面都是用戶體驗的重要組成部分,它能提高整個軟件的品質
百度地圖定位簽到功能,百度地圖簽到 1. 注意 key 一定要在activity 前面 <application android:allowBackup=tr