編輯:關於Android編程
private class DownloadFilesTask extends AsyncTask在幾個我們可以復寫的方法中,除了doInBackgroud方法別的都是執行在主線程中的。 當我們使用一個AsyncTask的時候我們必須指定3個泛型類型和實現doInBackground()函數。{ protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } }
public abstract class AsyncTask這是AnsyncTask需要定義的3個泛型數據。 第一個Params是我們需要指定重寫的doInBackgroud的參數
protected abstract Result doInBackground(Params... params);第二個progress是用於指定更新進度方法傳入的參數
protected void onProgressUpdate(Progress... values) {
}
第三個Result是用於我們指定doInBackgroun返回值和onPostExecute方法的參數
protected void onPostExecute(Result result) {
}
必須要實現的abstract方法doInBackgroud,就是我們需要在後台做的任務。
整個執行流程
上面是官網提供的各種API,並且具有cancel, get等方法(是不是很熟悉,AsyncTask中就是包含一個FutureTask)。executeOnExecutor執行方法中允許我們自己定義Executor,也就是說我們可以用線程池去Execute去執行也可以用Thread。
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);//調用另外一個execute方法,並且傳入默認的Executor
}
public final AsyncTask executeOnExecutor(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);//執行
return this;
}
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//AsyncTask靜態,靜態,靜態的變量
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//volatile保證多線程下數據的可見性,但是注意無法保證原子性(不理解也沒有關系)
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();//雙向隊列
Runnable mActive;
public synchronized void execute(final Runnable r) {//這個方法是線程安全的
mTasks.offer(new Runnable() {//將傳入的Runnable
public void run() {
try {
r.run();//執行異步任務
} finally {
scheduleNext();//當一個異步任務執行完成之後必定會調用這個方法,不管是否正常結束
}
}
});
if (mActive == null) {//在當前無異步執行的時候調用
scheduleNext();
}
}
protected synchronized void scheduleNext() {//線程安全
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
sDefaultExecutor是靜態內部類SerialExecutor的一個靜態實例。這個變量是用來執行所有異步操作,我們看execute將傳入的Runnable封裝成另外一個Runnable,以便在執行run方法後執行scheduleNext()方法,並且入隊,如果沒有異步操作的話就會調用scheduleNext()方法。scheduleNext()是調用mTask中取出一個元素,放入THREAD_POOL_EXECUTOR來執行,THREAD_POOL_EXECUTOR其實是一個是一個ThreadPoolExecutor的實例,每次執行異步任務都是放入一個線程池中執行。從上面的代碼可以看出,每次線程池中只有一個線程在運行,如果當前有線程在運行的話,那麼只會將傳入的Runnable入隊,等待執行完畢後調用,並且所有的異步都是由duque來保存的所以所有任務執行順序按 。
也就是說在默認的Executor中執行異步操作,因為sDefaultExecutor是一個靜態類,所有的異步操作都是一個一個進行的,而且先後有序,我猜想這就是為什麼google建議你運行短時間的原因,如果一個異步花太多時間執行,那麼必將導致別的異步任務也將很長時間執行完成,降低體驗。
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//獲取虛擬機的處理器核心數
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//線程池的核心線程數
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//線程池最大線程數
private static final int KEEP_ALIVE_SECONDS = 30;//線程池超過核心線程
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 ThreadFactory sThreadFactory = new ThreadFactory() {//創建線程池每個線程的工廠
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//為每個線程起名
}
};
上面是對線程池各種參數設置,
private final WorkerRunnable mWorker;
private final FutureTask mFuture;
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 static abstract class WorkerRunnable implements Callable {
Params[] mParams;
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
可以看出mWorker是一個實現了Callable接口和可以保存mParams的一個實例。調用doInBackgroud和postResult,返回結果。mFuture將mWorker封裝成一個FutureTask對象,那麼mWorker就可以被一個實現了Executor接口的類所調用了。並且在mFuture中保證如果沒有執行Task的話調用PostResultIFNotInvoked,這個方法如果發現task沒有被執行,那麼回去調用postResult(result),用於完成onPostExecute的回調。
到現在我們可以整理下,我們調用execute(params),在調用execute線程執行onPreExecute()用默認的Executor異步執行封裝了mWorker的Future,在mWorker中執行了doInBackgroud並且將結果傳給postResult(result)。大致的流程理清楚了。那麼postResult(result)中有什麼?
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
private static Handler getHandler() {//根據單例模式獲取
synchronized (AsyncTask.class) {//對類上鎖,以防多次創建
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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;
}
}
}
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {//發送低啊用用onprogressUpdate的回調
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
在postResult中會直接生成一個綁定主線程的Message並且投遞給主線程,讓主線程調用finish,根據是否被取消了,調用具體的回調。publishProgress也是一樣通過向主線程投遞消息,讓主線程調用onProgressUpdate。
觀察者模式在Android開發場景中運用之通過Java源碼分析(一)
對於觀察者,很多開發者並不陌生,在日常開發過程中,這也是一個非常常見的設計模式,尤其是Android小伙伴,很多人都知道broadcast就是一個典型的觀察者模式,還有最
Android TextView實現跑馬燈效果的方法
本文為大家分享一個非常簡單但又很常用的控件,跑馬燈狀態的TextView。當要顯示的文本長度太長,又不想換行時用它來顯示文本,一來可以完全的顯示出文本,二來效果也挺酷,實
如何開啟Android 4.4.x系統的ART模式
如今很多Android手機新品都已經預裝或可升級到Android 4.4.x版本了,而該版本最大特色就是引入了ART模式。那麼,如何才能啟動這個模式呢?AR
MTK6735(Android6.0)-按鍵燈的實現
一、按鍵燈的簡介最近調試一下按鍵燈,今天抽空順便把的流程分析了一下。按鍵燈也是一種led,它的使用規則如命名一樣,當按鍵按下亮燈,如果一定時間不操作的話,一會會滅燈。其實