中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

AsyncTask怎么在Android中使用

發布時間:2021-05-17 17:22:55 來源:億速云 閱讀:271 作者:Leah 欄目:移動開發

這篇文章給大家介紹AsyncTask怎么在Android中使用,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

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的系統中會為單線程執行(即我們上面代碼的分析)

Android是什么

Android是一種基于Linux內核的自由及開放源代碼的操作系統,主要使用于移動設備,如智能手機和平板電腦,由美國Google公司和開放手機聯盟領導及開發。

關于AsyncTask怎么在Android中使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

上栗县| 铁力市| 兴安盟| 铜川市| 安康市| 汤阴县| 普陀区| 舟曲县| 衡山县| 宣威市| 台州市| 皋兰县| 武鸣县| 通道| 阿尔山市| 德安县| 郧西县| 资阳市| 盈江县| 积石山| 巩义市| 凤凰县| 玉门市| 墨脱县| 吴旗县| 兴宁市| 石台县| 克山县| 延边| 宁陕县| 陇川县| 新野县| 湖州市| 乌审旗| 当雄县| 翁源县| 固阳县| 东莞市| 女性| 滨州市| 洛南县|