編輯:關於Android編程
用於快速開啟異步任務,處理耗時操作。在線程池中處理異步任務,同時可以將進度和處理結果提交到主線程處理。
Params 表示傳入doInBackground參數的類型
Progress 表示後台任務執行進度的類型
Result 表示後台任務執行完成後返回結果的類型
若不需要傳入具體的參數,傳入Void即可
onPreExecute 執行任務之前,UI線程,在doInBackground執行之前
doInBackground 執行後台任務,子線程,can call publishProgress to publish updates on the UI thread
onProgressUpdate 進度更新,UI線程
onPostExecute 任務完成時,UI線程
onCancelled 任務取消時,並且onPostExecute不會執行,UI線程
InternalHandler AsyncTask內部Handler,處理任務的提交與更新的消息
SerialExecutor 串行線程池,用於任務調度,任務排隊,一次只能執行一個任務
THREAD_POOL_EXECUTOR 線程池的實現者,用於真正執行任務
WorkerRunnable 實現了Callable接口,用於後台計算
1、 onPreExecute , 執行任務之前,運行在UI線程,在doInBackground執行之前
2、 Result = doInBackground() , 執行後台任務,返回執行結果,在線程池中執行,配合publishProgress來更新任務進度
3、 onProgressUpdate , 在doInBackground方法中調用publishProgress方法,用於進度更新,運行在UI線程(通過內部handler切換到主線程)
4、 onPostExecute , 運行在UI線程,處理運行結果(通過內部handler切換到主線程)
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { //實例化WorkerRunnable對象 mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; // 實例化FutureTask mFuture = new FutureTask (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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
mWorker即WorkerRunnable對象,它是一個抽象類,並實現了Callable接口,用於計算一個任務
private static abstract class WorkerRunnableimplements Callable { Params[] mParams; }
mFuture即FutureTask對象,下面用到了如下構造,
public FutureTask(Callablecallable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
execute方法如下,它調用了executeOnExecutor方法,可以看到默認使用了sDefaultExecutor,即SerialExecutor
public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
executeOnExecutor方法,此方法首先檢查運行狀態並賦以新狀態,之後回調onPreExecute方法,並給mWorker賦以參數,最後讓Executor執行任務,並返回AsyncTask對象。
public final AsyncTaskexecuteOnExecutor(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); // 傳參FutureTask對象 return this; }
exec即Executor對象,默認使用SerialExecutor(串行線程池),用於調度任務排隊順序執行。通過exec.execute(mFuture)開啟任務調度,當有任務執行時,其他任務等待。mTasks即ArrayDeque,它是一個雙端隊列。第一次添加任務時,mTasks.offer將新任務添加到任務隊列尾部,此時mActive這個Runnable為空,所以會直接走判斷是否為空中的scheduleNext方法,並在此方法中通過THREAD_POOL_EXECUTOR.execute(mActive)開啟執行任務。後續任務會走finally中的scheduleNext,此時mActive不為空。當執行r.run()方法,即調用了FutureTask對象的run方法
private static class SerialExecutor implements Executor { final ArrayDequemTasks = new ArrayDeque (); 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); } }
FutureTask對象的run方法如下,callable對象即是在構造FutureTask對象時傳入的mWorker,c.call()即在run方法中調用了mWorker的call方法,並將結果保存在result,call方法運行於子線程
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callablec = callable; // callable對象即是在構造FutureTask對象時傳入的mWorker 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); } }
WorkerRunnable對象的call方法如下,它調用了doInBackground方法並將其返回值作為參數傳給postResult方法。到此調用了doInBackground方法,它運行在線程池中
public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); }
postResult方法,它會給AsyncTask內部的InternalHandler發送任務完成信息
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; }
InternalHandler如下,當消息類型為MESSAGE_POST_RESULT,通過finish方法完成執行結果的提交。當消息類型為MESSAGE_POST_PROGRESS時,回調更新進度onProgressUpdate方法。通過內部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; } } }
finish方法如下,當任務沒有取消時,調用onPostExecute,否則調用onCancelled。都運行在主線程
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
publishProgress,在doInBackground方法中調用,用以更新進度。此方法會向InternalHandler發送MESSAGE_POST_PROGRESS消息,以在UI線程更新進度
/** * This method can be invoked from {@link #doInBackground} to * publish updates on the UI thread while the background computation is * still running. Each call to this method will trigger the execution of * {@link #onProgressUpdate} on the UI thread. * * {@link #onProgressUpdate} will note be called if the task has been * canceled. * * @param values The progress values to update the UI with. * * @see #onProgressUpdate * @see #doInBackground */ protected final void publishProgress(Progress... values) { if (!isCancelled()) { sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
案例簡單模擬求和運算,並查看各個方法運行的線程
在MainActivity中自定義異步任務類繼承AsyncTask
class BackTask extends AsyncTask{ @Override protected void onPreExecute() { Log.e("TAG", "onPreExecute-任務執行之前,當前線程:"+Thread.currentThread().getName()); super.onPreExecute(); } @Override protected Integer doInBackground(Integer... params) { Log.e("TAG", "doInBackground-任務執行中... ,當前線程:"+Thread.currentThread().getName()); int N = params[0]; int count = 0; int total = 0; // 計算總和 Integer progress = 0; // 進度 while (count < N) { ++count; total += count; progress = count * 100 / N; publishProgress(progress); } return total; } @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); Log.e("TAG", "onPostExecute-執行結果,運算總和為" + result+" ,當前線程: "+Thread.currentThread().getName()); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.e("TAG", "onProgressUpdate-當前進度:" + values[0] + "%"+",當前線程:"+Thread.currentThread().getName()); } }
在onCreate方法中開啟任務
new BackTask().execute(100);
運行結果如下
09-07 08:33:53.508: E/TAG(2710): onPreExecute-任務執行之前,當前線程:main 09-07 08:33:53.508: E/TAG(2710): doInBackground-任務執行中... ,當前線程:AsyncTask #2 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:1%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:2%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:3%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:4%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:5%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:6%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:7%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:8%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:9%,當前線程:main 09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:10%,當前線程:main ... ... ... ... (省略部分輸出) 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:90%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:91%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:92%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:93%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:94%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:95%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:96%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:97%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:98%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:99%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:100%,當前線程:main 09-07 08:33:53.608: E/TAG(2710): onPostExecute-執行結果,運算總和為5050 ,當前線程: main
本菜開源的一個自己寫的Demo,希望能給Androider們有所幫助,水平有限,見諒見諒… https://github.com/zhiaixinyang
首先,登陸到Github上並創建一個新repository。在屏幕右上角,點擊“+”標記,並且選擇“New repository&rd
在android中的Touch分發中,經常可以看到從ACTION_DOWN->ACTION_MOVE->ACTION_UP,當我們不了解它是如何分發的話總感覺
以前做項目大多用的radiobutton,今天用tablayout來做一個tab切換頁面的的效果.實現的效果就是類似QQ.微信的頁面間(也就是Fragment間)的切換.