編輯:關於Android編程
AsyncTask異步任務類,允許在UI線程中進行後台操作和發布結果到UI線程中,一般使用多操作中,這個類的基本用法可以參照博主寫的另一邊博文http://blog.csdn.net/nzsdyun123/article/details/22215589這裡有講述AsyncTask的基本用法,今天我也按照上篇分析Handler機制那樣帶領大家來分析下AsyncTask的流程。
我們一般是這樣來開始啟動AsyncTask的:
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute(path);
這裡MyAysncTask是AysncTask的子類,這裡我們使用AsyncTask的時候也是一般繼承AysncTask類,重寫其方法,我們查看AysncTask的源碼發現:
/**
*
AsyncTask enables proper and easy use of the UI thread. This class allows to
* perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.
*
*
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the java.util.concurrent
pacakge such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.
AsyncTask是後台UI線程,通過發布結果到UI線程中,同時這裡也給我們介紹了AsyncTask被設計成Thread和Handler的一個助手類,適用於短時的線程操作,長時的線程操作被推薦適用線程池ThreadPoolExecutor來解決,及其他的一些基礎用法等,從這裡的簡介中,提到AsyncTask被設計成Thread和Handler的一個助手類?我們這時就要想AsyncTask是不是對Thread+Handler的一個封裝?答案是這樣嗎?我們帶著疑問來分析:
當我們調用myAsyncTask.execute(path);這語句時,這時AsyncTask就開始正式工作了。我們來進入源碼分析這句:
public final AsyncTask
return executeOnExecutor(sDefaultExecutor, params);
}
這裡函數被設計成接收三個泛型數據類型的類,同時參數被設計成可變參數,可以根據實際需求動態的傳入參數的個數。我們接著看跟蹤 return executeOnExecutor(sDefaultExecutor, params);
public final AsyncTask
Params... params) {
if (mStatus != Status.PENDING) {//尚未創建AsyncTask
switch (mStatus) {
case RUNNING://有AsyncTask正在後台運行,拋出異常
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED://有AsyncTask任務已完成
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;
}
從上述分析可以知道當前UI線程的AsyncTask對象不能多次調用execute方法,關鍵的是我們看這幾句
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
追蹤onPreExecute();可以發現這是一個空實現方法:
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
protected void onPreExecute() {
}
子類可以重寫它,運行在UI線程,在doInBackground方法之前,從這裡我們可以知道,既然onPreExecute函數運行在UI線程中,所以我們可以在這做些資源的初始化的工作。接著來分析 mWorker.mParams = params;這句是將參數賦值給mWorker對象的參數。所以我們追蹤mWorker對象發現:
private final WorkerRunnable
private final FutureTask
它是AsyncTask的類類型對象,那WorkerRunnable到底是什麼呢?追蹤源碼可知:
private static abstract class WorkerRunnable
Params[] mParams;
}
它是一個抽象類,實現了Callable回調接口,用於從不同的線程來獲取結果Result,OK,我們接著分析:
exec.execute(mFuture);從executeOnExecutor函數聲明中可以看出exec是Executor的對象,Excutor?哇,這不就是線程池的運用嘛(線程池知識這裡不講解),這裡簡單講下Excutor,Excutor是一個接口,此接口提供一種將任務提交與每個任務將如何運行的機制(包括線程使用的細節、調度等)分離開來的方法。簡單講就是方便線程的創建和使用。那麼exec.execute(mFuture);就是執行線程,那這個mFuture肯定是一個Runnable或者實現Runnable接口的類,追蹤mFuture:
private final FutureTask
FutureTask?這又是什麼呢?我們查看JDK幫助文檔可知:
public class FutureTask
extends Object
implements RunnableFuture
它是繼承了Object對象,實現RunnableFuture接口的類,當然RunnableFuture實現了Runnable接口,果不其然,由JDK可知
FutureTask是一個可取消的異步計算。利用開始和取消計算的方法、查詢計算是否完成的方法和獲取計算結果的方法。簡單來講就是獲取提供一些方法來開始和取消線程,同時可以獲取線程運行後的結果。那麼FutureTask和WorkerRunnable對象又是什麼時候開始創建的呢?追蹤可以發現它們是在我們創建AsyncTask對象時就給我們創建好了:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable
public Result call() throws Exception {
mTaskInvoked.set(true);//設置標志值
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//設置線程優先級
//noinspection unchecked
return postResult(doInBackground(mParams));//根據外部傳入的參數調用doInBackground方法,並將結果傳給postResult函數
}
};
mFuture = new FutureTask
//創建FutureTask對象,重寫done方法
@Override
protected void done() {
try {
postResultIfNotInvoked(get());//等到線程執行完成,通過get方法獲取線程運行後的結果,傳給postResultIfNotInvoked方法
} 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);
}
}
};
}
原來這兩個對象在AsyncTask類創建的時候就給預先創建好了,前面說到WorkerRunnable是一個實現了Runnable接口的類,當系統執行到exec.execute(mFuture);這句時,這時就會執行線程裡的WorkerRunnable的方法,這裡們可以看到,AsyncTask的設計者巧妙的使用回調,將需要在線程中運行的語句又交到了我們開發應用者手上,我們查看doInBackground(mParams)就可以知道:
protected abstract Result doInBackground(Params... params);
這是一個抽象的方法,我們子類可以實現它,當然這些語句會運行在另一個線程中,Ok這時我們查看postResult和postResultIfNotInvoked方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
postResultIfNotInvoked方法最後也是調用postResult方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult
message.sendToTarget();
return result;
}
從這裡可以看出,向sHandler所在的線程發送一個消息,並將線程運行後的結果回傳過去,ok,這裡我們分析sHandler對象的類:
private static final InternalHandler sHandler = new InternalHandler();
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;
}
}
}
從上面可以知道,此Handler類接收兩個消息:MESSAGE_POST_RESULT線程執行完畢後消息,MESSAGE_POST_PROGRESS進度更新消息
result.mTask.finish(result.mData[0]);
我們從這句語句找到finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
要麼是調用 */
@SuppressWarnings({"UnusedParameters"})
protected void onCancelled(Result result) {
onCancelled();
}
onCancelled來取消AysncTask,不然就是等待線程運行完成後,提交給onPostExecute(result);方法處理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
所以,我們可以在子類中重寫onPostExecute這個方法時,獲取其結果,而MESSAGE_POST_PROGRESS消息是將結果交於onProgressUpdate(result.mData);處理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
這裡一般是我們重寫時獲取進度來進行進度條更新的,那這個消息MESSAGE_POST_PROGRESS又從哪裡向handler發送的呢?我們繼續追查:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
}
}
在這個方法裡發送的,這就我們可以解釋的同,為什麼我們調用
publishProgress的時候,可以在onProgressUpdate接收結果並更新UI,publishProgress是通過handler向創建AsyncTask所在的線程中發送消息並將結果回傳過去的。到目前為止,AsyncTask的源碼分析就分析的差不多了,這也驗證了我們剛開始的猜想,AsyncTask是對Thread+Handler的封裝,當然這裡不是直接使用Thread的,而已使用靜態線程池來進行的,這個查看AsyncTask的各個屬性聲明就可以知道,當然這也帶來了一些限制,那就是線程數不能創建太多。
第一,這貨速度太快,第二,模仿真機環境,第三,秒殺任何Android模擬器包括真機,不多說上圖,我忒忙! 官網:http://www.genymotion.com/鏡像圖
菜單包括選項菜單(OptionMenu)、上下文菜單(ContextMenu)、子菜單(SubMenu). 創建子菜單(SubMenu)的步驟: 1、重寫Activity
Android系統支持原生動畫,這為應用開發者開發絢麗的界面提供了極大的方便,有時候動畫是很必要的,當你想做一個滑動的特效的時候,如果苦思冥想都搞不定,那麼你可以考慮下動
寫在前面的廢話一般Android開發者都會使用Eclipse,Android studio觀察log輸出,其實後台是使用adb來打印log的,這裡介紹的是如何讓log輸出