## AsnycTask的內部的實現機制
### 寫在前面
我們為什么要用AsnycTask。 在Android程序開始運行的時候會單獨啟動一個進程,默認情況下所有 這個程序操作都在這個進程中進行。一個Android程序默認情況下只有 一個進程,但是一個進程卻是可以有許線程的。
我們通常會把一些比較耗時的操作,例如網絡請求、數據庫操作、復雜計算等邏輯都封裝到單獨的線程,這樣就可以避免阻塞主線程。
### 內部機制
主要分為兩大部分:
1、與主線的交互,它內部實例化了一個靜態的自定義類InternalHand- ler,這個類是繼承自Handler的,在這個自定義類中綁定了一個叫做 AsyncTaskResult的對象,每次子線程需要通知主線程,就調用send- ToTarget發送消息給handler。然后在handler的handleMessage 中AsyncTaskResult根據消息的類型不同(例如MESSAGE POST- PROGRESS會更新進度條 , MESSAGEPOST CANCEL取消任務)而 做不同的操作,值得一提的是,這些操作都是在UI線程進行的,意味著, 從子線程一旦需要和UI線程交互,內部自動調用了handler對象把消息 放在了主線程了。
~~~
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void More ...done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
`+ "doInBackground()", t);`
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void More ...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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
~~~
2、AsyncTask內部調度,雖然可以新建多個AsyncTask的子類的實例, 但是AsyncTask的內部Handler和ThreadPoolExecutor都是static 的,這么定義的變量屬于類的,是進程范圍內共享的,所以AsyncTask 控制著進程范圍內所有的子類實例,而且該類的所有實例都共用一個線 程池和Handler。
~~~
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread More ...newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_
SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static final int MESSAGE_POST_CANCEL = 0x3;
~~~
從代碼還可以看出,默認核心線程池的大小是5,緩存任務隊列是10。 意味著,如果線程池的線程數量小于5,這個時候新添加一個異步任 務則會新建一個線程;如果線程池的數量大于等于5,這個時候新建一 個異步任務這個任務會被放入緩存隊列中等待執行。
### 注意的地方
- 由于Handler需要和主線程交互,而Handler又是內置于AsnycTask中的,所以, AsyncTask的創建必須在主線程。
- AsyncTaskResult的doInBackground(mParams)方法執行異步任務運行在子線 程中,其他方法運行在主線程中,可以操作UI組件。
- 不要手動的去調用AsyncTask的onPreExecute, doInBackground, publishPro- gress, onProgressUpdate, onPostExecute方法,這些都是由Android系統自 動調用的
- 一個任務AsyncTask任務只能被執行一次。
- 運行中可以隨時調用cancel(boolean)方法取消任務,如果成功調用isCancelled() 會 返 回 true,并 且 不 會 執 行 onPostExecute() 方 法 了,取 而 代 之 的 是 調 用 onCancelled() 方法。而且從源碼看,如果這個任務已經執行了這個時候調用 cancel是不會真正的把task結束,而是繼續執行,只不過改變的是執行之后的回 調方法是onPostExecute還是onCancelled。
--------------
### Activity OnConfiguration
1、如果你的App沒有明確指定屏幕 方向和configChanges時,當用戶旋轉屏幕的時候Activity就會重新 啟動,而這個時候您的異步加載數據的線程可能正在請求網絡。當一 個新的Activity被重新創建之后,可能由重新啟動了一個新的任務去 請求網絡,這樣之前的一個異步任務不經意間就泄露了,假設你還在 onPostExecute寫了一些其他邏輯,這個時候就會發生意想不到異常。
2、一般簡單的數據類型的,對付configChanges我們很好處理,我們直接 可 以 通 過onSaveInstanceState() 和 onRestoreInstanceState() 進 行 保 存 與 恢 復。
3、對于AsyncTask,我們可以用到Square開源的EventBus類庫http://square.github.io/ otto/。首先自定義一個AsyncTask的子類,在onPostExecute方法中, 把返回結果拋給事件總線。
~~~
@Override
protected String doInBackground(Void... params) {
Random random = new Random();
final long sleep = random.nextInt(10);
try {
Thread.sleep(10 * 6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Slept for " + sleep + " seconds";
}
@Override
protected void onPostExecute(String result) {
MyBus.getInstance().post(new AsyncTaskResultEvent(result));
}
~~~
在Activity的onCreate中注冊這個事件總線,這樣異步線程的消息就會 被otta分發到當前注冊的activity,這個時候返回結果就在當前activity 的onAsyncTaskResult中了。
~~~
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.otto_layout);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
new MyAsyncTask().execute();
}
});
MyBus.getInstance().register(this);
}
@Override
protected void onDestroy() {
MyBus.getInstance().unregister(this);
super.onDestroy();
}
@Subscribe
public void onAsyncTaskResult(AsyncTaskResultEvent event) {
Toast.makeText(this, event.getResult(), Toast.LENGTH_LONG).show();
}
~~~
- 前言
- 內存溢出的解決方案
- 安卓消息推送解決方案
- 語言識別和聊天機器人的實現
- 抽屜效果的實現(DrawerLayout和SlidingMenu的對比)
- 植物大戰僵尸經典開發步驟
- 屏幕適配全攻略
- 安卓圖像處理入門教程
- android開發常用工具箱
- java基礎知識總結
- 剖析軟件外包項目
- java基礎知識——網絡編程、IO流
- 安卓性能優化手冊
- 電商活動中刮刮卡的實現
- Android系統的安全設計與架構
- AsnycTask的內部的實現機制
- Android應用UI設計流程
- 數據結構與算法,每日一道
- html5全解析
- 深入解讀XML解析
- 新聞客戶端案例開發
- 細說Http協議
- win10+ubuntu雙系統安裝方案
- 隨機驗證碼實現案例
- 動態數組的實現案例
- 猜拳游戲案例
- 商業級項目——基金客戶端的架構設計與開發(上)