編輯:關於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 WorkerRunnable implements 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(this, result));
message.sendToTarget();
return result;
}
在postResult中會發出消息通知Handler,
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的整個流程都很清楚了。
AndroidStudio代碼檢查,Lint檢查,還有注解
一,IntelliJ 代碼檢查IntelliJ IDEA的具有強大,快速,靈活的靜態代碼分析。它可以檢測編譯器和運行時錯誤,提出改進和完善,甚至在編譯之前。代碼檢查基礎(
Android App中使用LinearLayout進行居中布局的實例講解
要想讓您的控件水平居中或垂直居中其實很簡單,只要在控件的上一級中設置【android:gravity=center】屬性即可如:<LinearLayout xmln
Android4.4.2源碼分析之WiFi模塊(一)
已經寫了幾篇關於Android源碼的,源碼代碼量太大,所以如果想分析某個模塊可能不知如何下手,說一下思路1,分析源碼英文閱讀能力要夠,想要分析某個模塊一般找模塊對應的英文
Android 性能分析工具之 TraceView 使用說明
TraceView 是 Android 平台配備一個很好的性能分析的工具。它可以通過圖形化的方式讓我們了解我們要跟蹤的程序的性能,並且能具體到 method。TraceV