編輯:關於Android編程
相信大家對AsyncTask都不陌生,對於執行耗時任務,然後更新UI是一把利器,當然也是替代Thread + Handler 的一種方式。如果你對Handler機制還不了解,請看:Android 異步消息處理機制 讓你深入理解 Looper、Handler、Message三者關系。
相信大家都寫過這樣的代碼:
package com.example.zhy_asynctask_demo01;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = MainActivity;
private ProgressDialog mDialog;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(false);
new MyAsyncTask().execute();
}
private class MyAsyncTask extends AsyncTask
{
@Override
protected void onPreExecute()
{
mDialog.show();
Log.e(TAG, Thread.currentThread().getName() + onPreExecute );
}
@Override
protected Void doInBackground(Void... params)
{
// 模擬數據的加載,耗時的任務
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(80);
} catch (InterruptedException e)
{
e.printStackTrace();
}
publishProgress(i);
}
Log.e(TAG, Thread.currentThread().getName() + doInBackground );
return null;
}
@Override
protected void onProgressUpdate(Integer... values)
{
mDialog.setProgress(values[0]);
Log.e(TAG, Thread.currentThread().getName() + onProgressUpdate );
}
@Override
protected void onPostExecute(Void result)
{
// 進行數據加載完成後的UI操作
mDialog.dismiss();
mTextView.setText(LOAD DATA SUCCESS );
Log.e(TAG, Thread.currentThread().getName() + onPostExecute );
}
}
}
效果圖:

那麼大家一定好奇,AsyncTask在Android中是如何實現的,下面進行源碼分析:從我們的執行異步任務的起點開始,進入execute方法:
public final AsyncTask18行:設置當前AsyncTask的狀態為RUNNING,上面的switch也可以看出,每個異步任務在完成前只能執行一次。execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } 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; }
相信大家對22行出現的mWorker,以及23行出現的mFuture都會有些困惑。
mWorker找到這個類:
private static abstract class WorkerRunnableimplements Callable { Params[] mParams; }
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));
}
};
//….
}
private Result postResult(Result result) {
@SuppressWarnings(unchecked)
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
private static class AsyncTaskResult {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
看到這,我相信大家肯定會想到,在某處肯定存在一個sHandler,且復寫了其handleMessage方法等待消息的傳入,以及消息的處理。
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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
mWoker看完了,應該到我們的mFuture了,依然實在構造方法中完成mFuture的初始化,將mWorker作為參數,復寫了其done方法。
public AsyncTask() {
...
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 occured while executing doInBackground(),
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
16行:任務執行結束會調用:postResultIfNotInvoked(get());get()表示獲取mWorker的call的返回值,即Result.然後看postResultIfNotInvoked方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
如果mTaskInvoked不為true,則執行postResult;但是在mWorker初始化時就已經將mTaskInvoked為true,所以一般這個postResult執行不到。
exec為executeOnExecutor(sDefaultExecutor, params)中的sDefaultExecutor
下面看這個sDefaultExecutor
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
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);
}
}
}
可以看到sDefaultExecutor其實為SerialExecutor的一個實例,其內部維持一個任務隊列;直接看其execute(Runnable runnable)方法,將runnable放入mTasks隊尾;
public static final Executor THREAD_POOL_EXECUTOR
=new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到就是一個自己設置參數的線程池,參數為:
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 ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, AsyncTask # + mCount.getAndIncrement());
}
};
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(10);
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
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);
}
}
}
到此源碼解釋完畢,由於代碼跨度比較大,我們再回顧一下:
public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } 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; }
說了這麼多,我們好像忘了一個方法:publishProgress
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
也很簡單,直接使用sHandler發送一個消息,並且攜帶我們傳入的值;
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;
}
}
}
記得以前有個面試題經常會問道:AsyncTask運行的原理是什麼?有什麼缺陷?
以前對於缺陷的答案可能是:AsyncTask在並發執行多個任務時發生異常。其實還是存在的,在3.0以前的系統中還是會以支持多線程並發的方式執行,支持並發數也是我們上面所計算的128,阻塞隊列可以存放10個;也就是同時執行138個任務是沒有問題的;而超過138會馬上出現java.util.concurrent.RejectedExecutionException;
而在在3.0以上包括3.0的系統中會為單線程執行(即我們上面代碼的分析);
空說無憑:下面看測試代碼:
package com.example.zhy_asynctask_demo01;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = MainActivity;
private ProgressDialog mDialog;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(false);
for(int i = 1 ;i <= 138 ; i++)
{
new MyAsyncTask2().execute();
}
//new MyAsyncTask().execute();
}
private class MyAsyncTask2 extends AsyncTask
{
@Override
protected Void doInBackground(Void... params)
{
try
{
Log.e(TAG, Thread.currentThread().getName());
Thread.sleep(10000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
}
}
可以看到我for循環中執行138個異步任務,每個異步任務的執行需要10s;下面使用2.2的模擬器進行測試:
輸出結果為:
AsyncTask#1 - AsyncTask #128同時輸出
然後10s後,另外10個任務輸出。
可以分析結果,得到結論:AsyncTask在2.2的系統中同時支持128個任務並發,至少支持10個任務等待;
下面將138個任務,改成139個任務:
for(int i = 1 ;i <= 139 ; i++)
{
new MyAsyncTask2().execute();
}
運行結果:會發生異常:java.util.concurrent.RejectedExecutionException ; 於是可以確定僅支持10個任務等待,超過10個則立即發生異常。
簡單看一下源碼:
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
看ThreadPoolExecutor的execute方法:
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
private boolean addWorker(Runnable firstTask, boolean core) {
…
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
…
}
上面就是使用2.2模擬器測試的結果;
下面將系統改為4.1.1,也就是我的測試機小米2s
把線程數改為139甚至1000,你可以看到任務一個接一個的在那緩慢的執行,不會拋什麼異常,不過線程倒是1個1個的在那執行;
好了,如果現在大家去面試,被問到AsyncTask的缺陷,可以分為兩個部分說,在3.0以前,最大支持128個線程的並發,10個任務的等待。在3.0以後,無論有多少任務,都會在其內部單線程執行;
至此,AsyncTask源碼分析完畢,相信大家對AsyncTask有了更深的理解~~~
測試代碼點擊下載
Android 動畫解析(二) 補間動畫(Tween Animation)
上篇文章簡單描述了有關如何實現逐幀動畫(Frame Animation),如何還未了解逐幀動畫(Frame Animation)。今天這篇文章就來描述補間動畫(Tween
從零開始學android(Message消息機制.四十二.)
ndroid.os.Message的主要功能是進行消息的封裝,並且同時可以指定消息的操作形式。 No. 變量或方法 類型 描述 1 p
Android drawable文件夾的使用
開學到現在一直都在學著去搞明白一個簡單的游戲。寫完代碼之後,發現主界面顯示的某些圖片比正常的大了許多。本來以為是代碼寫錯了,反反復復,來來回回的檢查代碼,真心沒有錯誤。。
Android EventBus3.0使用及源碼解析
叨了個叨最近因為換工作的一些瑣事搞的我一個頭兩個大,也沒怎麼去學新東西,實在是有些愧疚。新項目用到了EventBus3.0,原來只是聽說EventBus的鼎鼎大名,一直沒