編輯:關於Android編程
前言:
雖然現在RxJava非常流行,但是還是覺得應該分析一下Android的原生異步線程實現。打算用2篇文章來過一下這個知識點。其中第一部分主要為使用例子,第二部分從源碼的角度來驗證那樣使用的原因。
第一篇
第二篇
我分析一個類的時候,都是習慣先看它有哪些成員,然後從入口開始慢慢理順成員間的邏輯。
有一條捷徑是先看Android API文檔,上面各個類都有總結,然後再看代碼。
這裡是API地址
AsyncTask的類結構如下:
內部類: private static class SerialExecutor implements Executor //串行執行器 public enum Status {PENDING, RUNNING, FINISHED} //task的三種狀態 private static class InternalHandler extends Handler //內部封裝的Handler private static abstract class WorkerRunnableimplements Callable //工作線程 private static class AsyncTaskResult
構造方法:public AsyncTask() //初始化了工作線程和執行回調
重要成員: private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//CPU核數 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心線程數 2-4之間 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大線程數 private static final int KEEP_ALIVE_SECONDS = 30;//生存時間 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//串行執行器 //Handler的2個消息類型, 0x1執行完畢, 0x2進度更新 private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2; private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//可以外部設置的執行器,默認是串行執行器 private static InternalHandler sHandler;//內部封裝的Handler,處理上面的2個消息 private final WorkerRunnablemWorker;//工作線程 private volatile Status mStatus = Status.PENDING;//task當前狀態,初始值為 PENDING
對外提供的接口: //下面3個executr都只能在UI線程中調用 public final AsyncTaskexecute(Params... params) //串行執行器 public final AsyncTask executeOnExecutor(Executor exec,Params... params) //自定義執行器,可以設置參數做並行計算
官方注釋如下
This method is typically used with {@link #THREAD_POOL_EXECUTOR} to * allow multiple tasks to run in parallel on a pool of threads managed by * AsyncTask, however you can also use your own {@link Executor} for custom * behavior.
public final boolean isCancelled() public final boolean cancel(boolean mayInterruptIfRunning) public final Result get() throws InterruptedException, ExecutionException //獲取執行結果 public final Status getStatus() public static void setDefaultExecutor(Executor exec) //設置自己的執行器
下面從AsyncTask的3個入口來分析它。
第一個串行執行入口:
public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
executeOnExecutor如下:
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;
從這裡可以看出為什麼execute只能調用一次,第二次調用的時候就會throw new IllegalStateException。
在執行execute前會先調用onPreExecute。
execute內容如下,
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); } }
從run方法可以看出來,execute方法加了鎖,只有當r.run()執行完畢後,才會scheduleNext執行下一個Runnable。
因此THREAD_POOL_EXECUTOR中的Runnable是串行執行的。
此外,可以看到,實際上execute是通過調用executeOnExecutor實現的,只不過指定傳入了串行執行器。
我們仍可以給executeOnExecutor傳入其它執行器來實現並行計算,
AsyncTask內部就維護了一個Java線程池,
public static final Executor THREAD_POOL_EXECUTOR; static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor; }
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心線程數 2-4之間 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大線程數 private static final int KEEP_ALIVE_SECONDS = 30;//生存時間
最後一個,
public static void execute(Runnable runnable) { sDefaultExecutor.execute(runnable); }它實際上也是調用是串行執行器來執行的,這不過是免去了不需要部分的初始化工作。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
回到AsyncTask的構造函數:
public AsyncTask() { mWorker = new WorkerRunnable() { 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); } }; 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 occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult在postResult中會發出消息通知Handler,(this, result)); message.sendToTarget(); return result; }
case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break;
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }finish會去調用onCancelled或者onPostExecute方法。
至此,AsyncTask的3個Step已經走過了。
onPreExecute -> doInBackGround -> onPostExecute
怎麼還少了一個onProgressUpdate呢?
直接找到onProgressUpdate的調用處,
case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break;Handler在收到消息MESSAGE_POST_PROGRESS的時候會去調用onProgressUpdate
這個消息哪裡發的呢?是在publishProgress方法中
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
還是要靠官方注釋
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.
這個方法要在doInBackGround中調用,而doInBackGround是一個抽象方法,要靠用戶自己去實現。
所以,其實谷歌並沒有幫你把所有事情都做好,至少沒有幫你計算線程進度。
這個進度還是要我們自己來算。
到此,AsyncTask的整個流程都很清楚了。
一,IntelliJ 代碼檢查IntelliJ IDEA的具有強大,快速,靈活的靜態代碼分析。它可以檢測編譯器和運行時錯誤,提出改進和完善,甚至在編譯之前。代碼檢查基礎(
要想讓您的控件水平居中或垂直居中其實很簡單,只要在控件的上一級中設置【android:gravity=center】屬性即可如:<LinearLayout xmln
已經寫了幾篇關於Android源碼的,源碼代碼量太大,所以如果想分析某個模塊可能不知如何下手,說一下思路1,分析源碼英文閱讀能力要夠,想要分析某個模塊一般找模塊對應的英文
TraceView 是 Android 平台配備一個很好的性能分析的工具。它可以通過圖形化的方式讓我們了解我們要跟蹤的程序的性能,並且能具體到 method。TraceV