亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android中AsyncTask的入門使用學習指南

2019-10-21 21:25:22
字體:
來源:轉載
供稿:網友

前言

AsyncTask異步任務,用于執行耗時任務并在UI線程中更新結果。

我們都知道,Android UI線程中不能執行耗時的任務,否則就會出現ANR。對于耗時的操作就需要放到子線程中操作,操作完成后需要通知UI線程進行更新等操作,這就需要Android的異步消息機制(創建一個Message對象,使用Handler發送出去,然后在Handler的handleMessage()方法中獲得剛才發送的Message對象,然后在這里進行UI操作)。

不過本文要說的是AsyncTask,其實早在Android 1.5版本就引入這個類,所以我知道大多數人對它的用法都已經非常熟悉了?;居梅ㄔ诰W上搜搜就有很多教程,然而,在使用時,仍需要注意其潛在的問題以及缺陷。

[TOC]

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) {   // 模擬數據的加載,耗時的任務   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();   Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");  } }}

如以上實例中,當UI線程中需求處理耗時的操作時,我們可以放在AsyncTask的doInBackground方法中執行,這個抽象的類,有幾個方法需要我們重新,除了doInBackground,我們可以在onPreExecute中為這個耗時方法進行一些預處理操作,同時我們在onPostExecute中對UI進行更新操作。實例中的publishProgress對應的回調是onProgressUpdate,這樣可以實時更新UI,提供更好的用戶體驗。

AsyncTask 原理

AsyncTask主要有二個部分:一個是與主線的交互,另一個就是線程的管理調度。雖然可能多個AsyncTask的子類的實例,但是AsyncTask的內部Handler和ThreadPoolExecutor都是進程范圍內共享的,其都是static的,也即屬于類的,類的屬性的作用范圍是CLASSPATH,因為一個進程一個VM,所以是AsyncTask控制著進程范圍內所有的子類實例。

1、與主線程交互

與主線程交互是通過Handler來進行的,因為本文主要探討AsyncTask在任務調度方面的,所以對于這部分不做細致介紹,感興趣的朋友可以繼續去看AsyncTask的源碼部分。

2、線程任務的調度

內部會創建一個進程作用域的線程池來管理要運行的任務,也就就是說當你調用了AsyncTask#execute()后,AsyncTask會把任務交給線程池,由線程池來管理創建Thread和運行Therad。對于內部的線程池不同版本的Android的實現方式是不一樣的:

AsyncTask 發展

接下來我們先簡單的了解一下AsyncTask的歷史

首先在android 3.0之前的版本,ThreadPool的限制是5個,線程的并發量是128個,阻塞隊列長度10,也就是說超過138個則會拋出異常。因此我們在使用的時候,一定要主要這部分限制,正確的使用。

到了在Android 3.0之后的,也許是Google也意識到這個問題,對AsyncTask的API做了調整:

· execute()提交的任務,按先后順序每次只運行一個也就是說它是按提交的次序,每次只啟動一個線程執行一個任務,完成之后再執行第二個任務,也就是相當于只有一個后臺線程在執行所提交的任務(Executors.newSingleThreadPool() )。

· 新增了接口executeOnExecutor()這個接口允許開發者提供自定義的線程池來運行和調度Thread,如果你想讓所有的任務都能并發同時運行,那就創建一個沒有限制的線程池(Executors.newCachedThreadPool() ),并提供給AsyncTask。這樣這個AsyncTask實例就有了自己的線程池而不必使用AsyncTask默認的。

· 新增了二個預定義的線程池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是新增的,它的作用是保證任務執行的順序,也就是它可以保證提交的任務確實是按照先后順序執行的。它的內部有一個隊列用來保存所提交的任務,保證當前只運行一個,這樣就可以保證任務是完全按照順序執行的,默認的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;  } 
  1. 從代碼中可以看出,execute()其實也是通過執行executeOnExecutor()方法,只是將其中的Executor設置為默認值。
  2. executeOnExecutor()中將當前AsyncTask的狀態為RUNNING,上面的switch也可以看出,每個異步任務在完成前只能執行一次。
  3. 接下來就執行了onPreExecute() ,當前依然在UI線程,所以我們可以在其中做一些準備工作。
  4. 將我們傳入的參數賦值給了mWorker.mParams
  5. 最后exec.execute(mFuture)

相信大家對代碼中出現的mWorker,以及mFuture都會有些困惑。接下來我們來看看mWorker找到這個類:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {   Params[] mParams; } 

可以看到是Callable的子類,且包含一個mParams用于保存我們傳入的參數,下面看初始化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在構造方法中完成了初始化,并且因為是一個抽象類,在這里new了一個實現類,實現了call方法,call方法中設置mTaskInvoked=true,且最終調用doInBackground(mParams)方法,并返回Result值作為參數給postResult方法.可以看到我們的doInBackground出現了,下面繼續看:

private Result postResult(Result result) {   @SuppressWarnings("unchecked")   Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,     new AsyncTaskResult<Result>(this, result));   message.sendToTarget();   return result; } 

可以看到postResult中出現了我們熟悉的異步消息機制,傳遞了一個消息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就是一個簡單的攜帶參數的對象。

看到這,我相信大家肯定會想到,在某處肯定存在一個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;    }   } } 

這里出現了我們的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT消息時,執行了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;  } 

可以看到,如果我們調用了cancel()則執行onCancelled回調;正常執行的情況下調用我們的onPostExecute(result);主要這里的調用是在handler的handleMessage中,所以是在UI線程中。最后將狀態置為FINISHED。

mWoker看完了,應該到我們的mFuture了,依然實在構造方法中完成mFuture的初始化,將mWorker作為參數,復寫了其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);     }    }   }; } 

任務執行結束會調用: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執行不到。好了,到了這里,已經介紹完了execute方法中出現了mWorker和mFurture,不過這里一直是初始化這兩個對象的代碼,并沒有真正的執行。下面我們看真正調用執行的地方。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的一個實例,其內部維持一個任務隊列;直接看其execute(Runnable runnable)方法,將runnable放入mTasks隊尾;再判斷當前mActive是否為空,為空則調用scheduleNext。方法scheduleNext,則直接取出任務隊列中的隊首任務,如果不為null則傳入THREAD_POOL_EXECUTOR進行執行。下面看THREAD_POOL_EXECUTOR為何方神圣:

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<Runnable> sPoolWorkQueue =    new LinkedBlockingQueue<Runnable>(10); 

看到這里,大家可能會認為,背后原來有一個線程池,且最大支持128的線程并發,加上長度為10的阻塞隊列,可能會覺得就是在快速調用138個以內的AsyncTask子類的execute方法不會出現問題,而大于138則會拋出異常。其實不是這樣的,我們再仔細看一下代碼,回顧一下sDefaultExecutor,真正在execute()中調用的為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個任務同時調用execute(s synchronized)方法,第一個任務入隊,然后在mActive = mTasks.poll()) != null被取出,并且賦值給mActivte,然后交給線程池去執行。然后第二個任務入隊,但是此時mActive并不為null,并不會執行scheduleNext();所以如果第一個任務比較慢,10個任務都會進入隊列等待;真正執行下一個任務的時機是,線程池執行完成第一個任務以后,調用Runnable中的finally代碼塊中的scheduleNext,所以雖然內部有一個線程池,其實調用的過程還是線性的。一個接著一個的執行,相當于單線程。

總結:

AsyncTask在并發執行多個任務時發生異常。其實還是存在的,在3.0以前的系統中還是會以支持多線程并發的方式執行,支持并發數也是我們上面所計算的128,阻塞隊列可以存放10個;也就是同時執行138個任務是沒有問題的;而超過138會馬上出現java.util.concurrent.RejectedExecutionException;而在在3.0以上包括3.0的系統中會為單線程執行(即我們上面代碼的分析)

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品视频26uuu| 久久久精品视频在线观看| 欧美巨大黑人极品精男| 国产黑人绿帽在线第一区| 91久久精品美女| 国产亚洲欧洲高清| 国内自拍欧美激情| 富二代精品短视频| 亚洲一区二区久久久久久久| 91网在线免费观看| 久久999免费视频| 欧美精品在线免费播放| 欧美另类69精品久久久久9999| 日韩电影大全免费观看2023年上| 国产91色在线|免| 欧美天天综合色影久久精品| 欧美黄色免费网站| 欧美视频专区一二在线观看| 日韩免费在线电影| 亚洲乱码一区av黑人高潮| 国产日韩欧美电影在线观看| 国产福利视频一区二区| 亚洲一区中文字幕在线观看| 欧美性资源免费| 亚洲综合在线做性| 在线性视频日韩欧美| 亚洲国产高清高潮精品美女| 亚洲毛片在线观看| 日韩av影院在线观看| 欧美日韩福利电影| 91久久精品久久国产性色也91| 中文字幕欧美在线| 亚洲精品99999| 理论片在线不卡免费观看| 国产一区二区三区在线视频| 美女撒尿一区二区三区| 亚洲精品91美女久久久久久久| 亚洲精品视频在线观看视频| 日本久久中文字幕| 欧美又大又粗又长| 亚洲久久久久久久久久| 国产精品永久免费| 国产精品羞羞答答| 国产一区二区免费| 中文国产亚洲喷潮| 在线观看欧美日韩国产| 91精品国产91久久久久久久久| 亚洲欧美中文字幕在线一区| 欧美一区二区三区免费观看| 欧美疯狂xxxx大交乱88av| 国产精品视频久久久久| 久久伊人免费视频| 青草热久免费精品视频| 亚洲福利小视频| 久久精品视频亚洲| 精品一区二区三区四区在线| 久久国产加勒比精品无码| 欧美日韩在线视频一区二区| 国内揄拍国内精品少妇国语| 欧美性生交大片免网| 国产一区二区丝袜| 国产精品精品久久久| 奇米四色中文综合久久| 精品性高朝久久久久久久| 日韩男女性生活视频| 国产精品aaaa| 欧美在线视频播放| 欧美综合第一页| 久久久久日韩精品久久久男男| 日韩中文字幕网| 亚洲成人黄色网址| 日韩精品在线观看一区二区| 俺也去精品视频在线观看| 免费91在线视频| 欧美中文字幕在线| 亚洲美女在线视频| 欧美日韩电影在线观看| 一区二区三区四区在线观看视频| 精品视频久久久久久| 亚洲最新视频在线| 久久欧美在线电影| 欧美综合在线第二页| 亚洲国产日韩欧美在线图片| 亚洲精品乱码久久久久久按摩观| 久久99热这里只有精品国产| 国产色综合天天综合网| 欧美日韩福利视频| 国产精品黄页免费高清在线观看| 91精品久久久久久久久久久| 亚洲a级在线观看| 中文字幕亚洲一区二区三区| 欧美在线视频观看| 精品人伦一区二区三区蜜桃免费| 国模gogo一区二区大胆私拍| 中文字幕久久久av一区| 亚洲国产日韩欧美在线99| 国产精品吴梦梦| 最新69国产成人精品视频免费| 亚洲第一福利在线观看| 欧美视频一区二区三区…| 色悠悠国产精品| 亚洲欧美日韩成人| 亚洲自拍小视频免费观看| 亚洲欧美成人精品| 久久综合伊人77777尤物| 国产在线视频2019最新视频| 欧美午夜xxx| 欧美一级大片在线免费观看| 国产欧美精品一区二区三区-老狼| 亚洲精品美女久久久| 成人精品久久一区二区三区| 国产精品三级在线| 日韩最新在线视频| 日韩资源在线观看| 国产成人在线一区二区| 亚洲女在线观看| 国外色69视频在线观看| 国产一区二区三区毛片| 亚洲一区二区三区久久| 欧美伦理91i| 欧美色图在线视频| 亚洲第一精品夜夜躁人人爽| 热门国产精品亚洲第一区在线| 欧美成人在线网站| 久久久视频免费观看| 欧美大片网站在线观看| 成人激情免费在线| 欧美壮男野外gaytube| 国产精品入口夜色视频大尺度| 久久99国产精品久久久久久久久| 亚洲国产一区二区三区在线观看| 亚洲黄色在线看| 92国产精品久久久久首页| 国产一区二区三区视频| 亚洲国产另类久久精品| 九色91av视频| 国产欧美精品va在线观看| 久久精品视频99| 精品国产一区久久久| 狠狠久久五月精品中文字幕| 亚洲成人av在线| 中文在线资源观看视频网站免费不卡| 国产精品视频在线播放| 欧美激情视频给我| 国内精品久久久久伊人av| 成人黄色av免费在线观看| 亚洲精品永久免费| 91精品视频一区| xxxxxxxxx欧美| 欧美三级免费观看| 国产欧美va欧美va香蕉在| 欧美高清第一页| 欧美在线视频在线播放完整版免费观看| 久久精品久久久久久| 久久久综合免费视频| 亚洲欧美日韩综合| 国产女精品视频网站免费| 国产成人精品日本亚洲专区61| 久久久亚洲欧洲日产国码aⅴ| 中文字幕亚洲无线码a| 久久久久久一区二区三区| 国产免费一区二区三区在线观看| 国产精品福利观看| 欧美日韩中文字幕在线|