您好,登錄后才能下訂單哦!
這篇文章給大家介紹AsyncTask怎么在Android中使用,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
AsyncTask 簡單使用
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private ProgressDialog mDialog; private AsyncTask mAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDialog = new ProgressDialog(this); mDialog.setMax(100); mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mDialog.setCancelable(false); mAsyncTask = new MyAsyncTask(); findViewById(R.id.tv).setOnClickListener(this); } @Override public void onClick(View view) { mAsyncTask.execute(); } private class MyAsyncTask extends AsyncTask<Void, Integer, Void> { @Override protected void onPreExecute() { mDialog.show(); Log.e(TAG, Thread.currentThread().getName() + " onPreExecute "); } @Override protected Void doInBackground(Void... params) { // 模擬數(shù)據(jù)的加載,耗時的任務(wù) 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) { // 進行數(shù)據(jù)加載完成后的UI操作 mDialog.dismiss(); Log.e(TAG, Thread.currentThread().getName() + " onPostExecute "); } } }
如以上實例中,當UI線程中需求處理耗時的操作時,我們可以放在AsyncTask的doInBackground方法中執(zhí)行,這個抽象的類,有幾個方法需要我們重新,除了doInBackground,我們可以在onPreExecute中為這個耗時方法進行一些預(yù)處理操作,同時我們在onPostExecute中對UI進行更新操作。實例中的publishProgress對應(yīng)的回調(diào)是onProgressUpdate,這樣可以實時更新UI,提供更好的用戶體驗。
AsyncTask 原理
AsyncTask主要有二個部分:一個是與主線的交互,另一個就是線程的管理調(diào)度。雖然可能多個AsyncTask的子類的實例,但是AsyncTask的內(nèi)部Handler和ThreadPoolExecutor都是進程范圍內(nèi)共享的,其都是static的,也即屬于類的,類的屬性的作用范圍是CLASSPATH,因為一個進程一個VM,所以是AsyncTask控制著進程范圍內(nèi)所有的子類實例。
1、與主線程交互
與主線程交互是通過Handler來進行的,因為本文主要探討AsyncTask在任務(wù)調(diào)度方面的,所以對于這部分不做細致介紹,感興趣的朋友可以繼續(xù)去看AsyncTask的源碼部分。
2、線程任務(wù)的調(diào)度
內(nèi)部會創(chuàng)建一個進程作用域的線程池來管理要運行的任務(wù),也就就是說當你調(diào)用了AsyncTask#execute()
后,AsyncTask會把任務(wù)交給線程池,由線程池來管理創(chuàng)建Thread和運行Therad。對于內(nèi)部的線程池不同版本的Android的實現(xiàn)方式是不一樣的:
AsyncTask 發(fā)展
接下來我們先簡單的了解一下AsyncTask的歷史
首先在android 3.0之前的版本,ThreadPool的限制是5個,線程的并發(fā)量是128個,阻塞隊列長度10,也就是說超過138個則會拋出異常。因此我們在使用的時候,一定要主要這部分限制,正確的使用。
到了在Android 3.0之后的,也許是Google也意識到這個問題,對AsyncTask的API做了調(diào)整:
· execute()提交的任務(wù),按先后順序每次只運行一個也就是說它是按提交的次序,每次只啟動一個線程執(zhí)行一個任務(wù),完成之后再執(zhí)行第二個任務(wù),也就是相當于只有一個后臺線程在執(zhí)行所提交的任務(wù)(Executors.newSingleThreadPool()
)。
· 新增了接口executeOnExecutor()
這個接口允許開發(fā)者提供自定義的線程池來運行和調(diào)度Thread,如果你想讓所有的任務(wù)都能并發(fā)同時運行,那就創(chuàng)建一個沒有限制的線程池(Executors.newCachedThreadPool()
),并提供給AsyncTask。這樣這個AsyncTask實例就有了自己的線程池而不必使用AsyncTask默認的。
· 新增了二個預(yù)定義的線程池SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR。其實THREAD_POOL_EXECUTOR并不是新增的,之前的就有,只不過之前(Android 2.3)它是AsyncTask私有的,未公開而已。THREAD_POOL_EXECUTOR是一個corePoolSize為5的線程池,也就是說最多只有5個線程同時運行,超過5個的就要等待。所以如果使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
就跟2.3版本的AsyncTask.execute()
效果是一樣的。而SERIAL_EXECUTOR是新增的,它的作用是保證任務(wù)執(zhí)行的順序,也就是它可以保證提交的任務(wù)確實是按照先后順序執(zhí)行的。它的內(nèi)部有一個隊列用來保存所提交的任務(wù),保證當前只運行一個,這樣就可以保證任務(wù)是完全按照順序執(zhí)行的,默認的execute()使用的就是這個,也就是executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)與execute()是一樣的。
AsyncTask 源碼簡析
這里我們從AsyncTask的起點開始分析,主要有 execute()
、executeOnExecutor()
。
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } public final AsyncTask<Params, Progress, Result> 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; }
從代碼中可以看出,execute()其實也是通過執(zhí)行executeOnExecutor()
方法,只是將其中的Executor設(shè)置為默認值。
在executeOnExecutor()
中將當前AsyncTask的狀態(tài)為RUNNING,上面的switch也可以看出,每個異步任務(wù)在完成前只能執(zhí)行一次。
接下來就執(zhí)行了onPreExecute()
,當前依然在UI線程,所以我們可以在其中做一些準備工作。
將我們傳入的參數(shù)賦值給了mWorker.mParams
最后exec.execute(mFuture)
相信大家對代碼中出現(xiàn)的mWorker,以及mFuture都會有些困惑。接下來我們來看看mWorker找到這個類:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
可以看到是Callable的子類,且包含一個mParams用于保存我們傳入的參數(shù),下面看初始化mWorker的代碼:
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; //... }
可以看到mWorker在構(gòu)造方法中完成了初始化,并且因為是一個抽象類,在這里new了一個實現(xiàn)類,實現(xiàn)了call方法,call方法中設(shè)置mTaskInvoked=true
,且最終調(diào)用doInBackground(mParams)
方法,并返回Result值作為參數(shù)給postResult方法.可以看到我們的doInBackground出現(xiàn)了,下面繼續(xù)看:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
可以看到postResult中出現(xiàn)了我們熟悉的異步消息機制,傳遞了一個消息message, message.what為MESSAGE_POST_RESULT;message.object= new AsyncTaskResult(this,result);
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
AsyncTaskResult就是一個簡單的攜帶參數(shù)的對象。
看到這,我相信大家肯定會想到,在某處肯定存在一個sHandler,且復(fù)寫了其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; } } }
這里出現(xiàn)了我們的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT消息時,執(zhí)行了result.mTask.finish(result.mData[0]);
其實就是我們的AsyncTask.this.finish(result)
,于是看finish方法
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
可以看到,如果我們調(diào)用了cancel()
則執(zhí)行onCancelled回調(diào);正常執(zhí)行的情況下調(diào)用我們的onPostExecute(result);
主要這里的調(diào)用是在handler的handleMessage中,所以是在UI線程中。最后將狀態(tài)置為FINISHED。
mWoker看完了,應(yīng)該到我們的mFuture了,依然實在構(gòu)造方法中完成mFuture的初始化,將mWorker作為參數(shù),復(fù)寫了其done方法。
public AsyncTask() { ... mFuture = new FutureTask<Result>(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); } } }; }
任務(wù)執(zhí)行結(jié)束會調(diào)用:postResultIfNotInvoked(get());get()表示獲取mWorker的call的返回值,即Result.然后看postResultIfNotInvoked方法
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }
如果mTaskInvoked不為true,則執(zhí)行postResult;但是在mWorker初始化時就已經(jīng)將mTaskInvoked為true,所以一般這個postResult執(zhí)行不到。好了,到了這里,已經(jīng)介紹完了execute方法中出現(xiàn)了mWorker和mFurture,不過這里一直是初始化這兩個對象的代碼,并沒有真正的執(zhí)行。下面我們看真正調(diào)用執(zhí)行的地方。execute方法中的:還記得上面的execute中的:exec.execute(mFuture)
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<Runnable> mTasks = new ArrayDeque<Runnable>(); 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的一個實例,其內(nèi)部維持一個任務(wù)隊列;直接看其execute(Runnable runnable)
方法,將runnable放入mTasks隊尾;再判斷當前mActive是否為空,為空則調(diào)用scheduleNext。方法scheduleNext,則直接取出任務(wù)隊列中的隊首任務(wù),如果不為null則傳入THREAD_POOL_EXECUTOR進行執(zhí)行。下面看THREAD_POOL_EXECUTOR為何方神圣:
public static final Executor THREAD_POOL_EXECUTOR =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到就是一個自己設(shè)置參數(shù)的線程池,參數(shù)為:
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<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10);
看到這里,大家可能會認為,背后原來有一個線程池,且最大支持128的線程并發(fā),加上長度為10的阻塞隊列,可能會覺得就是在快速調(diào)用138個以內(nèi)的AsyncTask子類的execute方法不會出現(xiàn)問題,而大于138則會拋出異常。其實不是這樣的,我們再仔細看一下代碼,回顧一下sDefaultExecutor,真正在execute()
中調(diào)用的為sDefaultExecutor.execute
:
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 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); } } }
可以看到,如果此時有10個任務(wù)同時調(diào)用execute(s synchronized)方法,第一個任務(wù)入隊,然后在mActive = mTasks.poll()) != null
被取出,并且賦值給mActivte,然后交給線程池去執(zhí)行。然后第二個任務(wù)入隊,但是此時mActive并不為null,并不會執(zhí)行scheduleNext();所以如果第一個任務(wù)比較慢,10個任務(wù)都會進入隊列等待;真正執(zhí)行下一個任務(wù)的時機是,線程池執(zhí)行完成第一個任務(wù)以后,調(diào)用Runnable中的finally代碼塊中的scheduleNext,所以雖然內(nèi)部有一個線程池,其實調(diào)用的過程還是線性的。一個接著一個的執(zhí)行,相當于單線程。
總結(jié):
AsyncTask在并發(fā)執(zhí)行多個任務(wù)時發(fā)生異常。其實還是存在的,在3.0以前的系統(tǒng)中還是會以支持多線程并發(fā)的方式執(zhí)行,支持并發(fā)數(shù)也是我們上面所計算的128,阻塞隊列可以存放10個;也就是同時執(zhí)行138個任務(wù)是沒有問題的;而超過138會馬上出現(xiàn)java.util.concurrent.RejectedExecutionException;
而在在3.0以上包括3.0的系統(tǒng)中會為單線程執(zhí)行(即我們上面代碼的分析)
Android是一種基于Linux內(nèi)核的自由及開放源代碼的操作系統(tǒng),主要使用于移動設(shè)備,如智能手機和平板電腦,由美國Google公司和開放手機聯(lián)盟領(lǐng)導(dǎo)及開發(fā)。
關(guān)于AsyncTask怎么在Android中使用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。