最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Android中用于線程處理的AsyncTask類(lèi)的用法及源碼

 更新時(shí)間:2016年05月06日 17:35:09   作者:然則  
這篇文章主要介紹了Android中用于線程處理的AsyncTask類(lèi)的用法及源碼,講到了實(shí)現(xiàn)AsyncTask中所用到的Handler及線程池等要點(diǎn),需要的朋友可以參考下

為什么要用AsyncTask
我們寫(xiě)App都有一個(gè)原則,主線程不能夠運(yùn)行需要占用大量CPU時(shí)間片的任務(wù),如大量復(fù)雜的浮點(diǎn)運(yùn)算,較大的磁盤(pán)IO操作,網(wǎng)絡(luò)socket等,這些都會(huì)導(dǎo)致我們的主線程對(duì)用戶的響應(yīng)變得遲鈍,甚至ANR,這些會(huì)使應(yīng)用的用戶體驗(yàn)變差,但是有時(shí)又的確需要執(zhí)行這些耗時(shí)的任務(wù),那么我們通??梢允褂肁syncTask或者new Thread
來(lái)處理,這樣把任務(wù)放入工作線程中執(zhí)行,不會(huì)占用主線程的時(shí)間片,所以主線程會(huì)及時(shí)響應(yīng)用戶的操作,如果使用new Thread來(lái)執(zhí)行任務(wù),那么如果需要中途取消任務(wù)執(zhí)行或者需要返回任務(wù)執(zhí)行結(jié)果,就需要我們自己維護(hù)很多額外的代碼,而AsyncTask是基于concurrent架包提供的并發(fā)類(lèi)實(shí)現(xiàn)的,上面的二個(gè)需求都已經(jīng)幫我們封裝了,這也是我們選擇AsyncTask的原因。

怎么用AsyncTask
我們還是簡(jiǎn)單介紹下AsyncTask一些使用示例。我們先新建一個(gè)類(lèi)DemoAsyncTask繼承AsyncTask,因?yàn)锳syncTask是抽象類(lèi),其中doInBackground方法必須重寫(xiě)。

private class DemoAsyncTask extends AsyncTask<String, Void, Void> {
 @Override
 protected void onPreExecute() {
  super.onPreExecute();
 }

 @Override
 protected Void doInBackground(String... params) {
  return null;
 } 

 @Override
 protected void onPostExecute(Void aVoid) {
  super.onPostExecute(aVoid);
 }

 @Override
 protected void onProgressUpdate(Void... values) {
  super.onProgressUpdate(values);
 }

 @Override
 protected void onCancelled(Void aVoid) {
  super.onCancelled(aVoid);
 }

 @Override
 protected void onCancelled() {
  super.onCancelled();
 }
}

DemoAsyncTask task = new DemoAsyncTask();
task.execute("demo test AsyncTask");
//task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, "test");
//myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "test");

簡(jiǎn)單分析下
上面就是AsyncTask最簡(jiǎn)單的使用方法,我們上面重寫(xiě)的方法中,onInBackground方法運(yùn)行在工作線程,其他的方法全部運(yùn)行在主線程,另外它的運(yùn)行方式Android提供給我們2個(gè)方法,上面都列出了。

1.第一個(gè)方法會(huì)使用默認(rèn)的Executor執(zhí)行我們的任務(wù), 其實(shí)也就是SERIAL_EXECUTOR,SERIAL_EXECUTOR我們其實(shí)也是可以通過(guò)方法去自定義的,Android幫我們的默認(rèn)實(shí)現(xiàn)是逐個(gè)執(zhí)行任務(wù),也就是單線程的,關(guān)于AsyncTask的任務(wù)執(zhí)行是單線程實(shí)現(xiàn)還是多線程實(shí)現(xiàn)還有一段很有意思的歷史,較早的版本是單線程實(shí)現(xiàn),從Android2.X開(kāi)始,Google又把它改為多線程實(shí)現(xiàn),后來(lái)Google發(fā)現(xiàn),多線程實(shí)現(xiàn)的話,會(huì)有很多需要保證線程安全的額外工作留給開(kāi)發(fā)者,所以從Android3.0開(kāi)始,又把默認(rèn)實(shí)現(xiàn)改為單線程了,今天我們演示的是Framwork代碼版本是21(Android5.0)。
2.同時(shí)也提供了多線程實(shí)現(xiàn)的接口,即我們上面寫(xiě)的最后一行代碼 AsyncTask.THREAD_POOL_EXECUTOR。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
 return executeOnExecutor(sDefaultExecutor, params);
}
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

其實(shí)相信大家平時(shí)工作學(xué)習(xí)中經(jīng)常使用AsyncTask,我們直接去看AsyncTask類(lèi)源碼(插一句題外話,平時(shí)大家也可以把自己工作學(xué)習(xí)中的心得體會(huì)總結(jié)一下,記下來(lái)~~)

public abstract class AsyncTask<Params, Progress, Result> {
....
}

AsyncTask抽象類(lèi),有三個(gè)泛型參數(shù)類(lèi)型,第一個(gè)是你需要傳遞進(jìn)來(lái)的參數(shù)類(lèi)型,第二個(gè)是任務(wù)完成進(jìn)度的類(lèi)型一般是Integer,第三個(gè)是任務(wù)完成結(jié)果的返回類(lèi)型,有時(shí)這些參數(shù)不是全部需要,不需要的設(shè)為Void即可,另外Result只有一個(gè),但Params可以有多個(gè)。
我們可以看到AsyncTask的默認(rèn)構(gòu)造器初始化了二個(gè)對(duì)象,mWorker和mFuture。

private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
 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));
  }
 };

 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);
   }
  }
 };

mWoker實(shí)現(xiàn)了Callback接口,Callback接口是JDK1.5加入的高級(jí)并發(fā)架包里面的一個(gè)接口,它可以有一個(gè)泛型返回值。

public interface Callable<V> {
/**
 * Computes a result, or throws an exception if unable to do so.
 *
 * @return computed result
 * @throws Exception if unable to compute a result
 */
V call() throws Exception;
}

FutureTask實(shí)現(xiàn)了RunnableFuture接口,RunnableFuture接口是JDK提供的,看名稱就知道它繼承了Runnable和Future接口,mFuture是FutureTask的一個(gè)實(shí)例,可以直接被Executor類(lèi)實(shí)例execute。我們來(lái)繼續(xù)看AsyncTask的execute方法。

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;
}

先調(diào)用onPreExecute()方法,此時(shí)還在主線程(嚴(yán)格來(lái)說(shuō)是調(diào)用AsyncTask執(zhí)行的線程),然后exec.execute(mFuture),把任務(wù)交給exec處理,execute mFuture其實(shí)就是invoke mWoker,然后調(diào)用postResult(doInBackground(mParams)),此時(shí)已經(jīng)運(yùn)行在工作線程池,不會(huì)阻塞主線程。然后給mHandler發(fā)送MESSAGE_POST_RESULT消息,然后調(diào)用finish方法,如果isCancelled,回調(diào)onCancelled,否則回調(diào)onPostExecute。

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

現(xiàn)在其實(shí)我們已經(jīng)把AsyncTask整個(gè)執(zhí)行任務(wù)的過(guò)程走完了,其中暴露給我們的那幾個(gè)回調(diào)方法也都走到了?,F(xiàn)在我們回過(guò)頭來(lái)看,AsyncTask其實(shí)只是對(duì)JDK 1.5提供的高級(jí)并發(fā)特性,concurrent架包做的一個(gè)封裝,方便開(kāi)發(fā)者來(lái)處理異步任務(wù),當(dāng)然里面還有很多細(xì)節(jié)處理的方法值得大家學(xué)習(xí),如任務(wù)執(zhí)行進(jìn)度的反饋,任務(wù)執(zhí)行原子性的保證等,這些留給大家自己學(xué)習(xí)了。

源碼分析
下面我們?cè)偕钊胍恍?,?lái)看AsyncTask的源碼。下面分析這個(gè)類(lèi)的實(shí)現(xiàn),主要有線程池以及Handler兩部分。

線程池
當(dāng)執(zhí)行一個(gè)AsyncTask的時(shí)候調(diào)用的是execute()方法,就從這個(gè)開(kāi)始看:

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; 
 //先執(zhí)行 onPreExecute
 onPreExecute(); 
 
 mWorker.mParams = params; 
 
 exec.execute(mFuture); 
 return this; 
} 

execute方法會(huì)調(diào)用executeOnExecutor。在這個(gè)方法中先檢查任務(wù)是否已經(jīng)執(zhí)行或者執(zhí)行結(jié)束,然后把任務(wù)標(biāo)記為running。最開(kāi)始執(zhí)行的是onPreExecute,接著把參數(shù)賦值給mWorker對(duì)象。這個(gè)mWorker是一個(gè)Callable對(duì)象,最終被包裝為FutureTask,代碼如下:

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

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)); 
  } 
 };
 
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); 
  } 
 } 
}; 

   
從上面的代碼可以看出,在mWorker對(duì)象中的call()方法會(huì)調(diào)用doInbackground,返回值交給postResult方法,這個(gè)方法通過(guò)Handler發(fā)送消息,這一點(diǎn)稍后再詳細(xì)分析。

在mWorker對(duì)象被封裝成FutureTask之后交由線程池執(zhí)行,從execute方法可以看出,使用的是sDefaultExecutor,它的值默認(rèn)為SERIAL_EXECUTOR,也就是串行執(zhí)行器,實(shí)現(xiàn)如下:

 

private static class SerialExecutor implements Executor { 
 //線性雙向隊(duì)列,用來(lái)存儲(chǔ)所有的AsyncTask任務(wù) 
 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 
 //當(dāng)前正在執(zhí)行的AsyncTask任務(wù) 
 Runnable mActive; 

 public synchronized void execute(final Runnable r) { 
  //將新的AsyncTask任務(wù)加入到雙向隊(duì)列中 
  mTasks.offer(new Runnable() { 
   public void run() { 
    try { 
     //執(zhí)行AsyncTask任務(wù) 
     r.run(); 
    } finally { 
     //當(dāng)前任務(wù)執(zhí)行結(jié)束后執(zhí)行下一個(gè)任務(wù)
     scheduleNext(); 
    } 
   } 
  }); 
  if (mActive == null) { 
   scheduleNext(); 
  } 
 } 

 protected synchronized void scheduleNext() { 
  //從任務(wù)隊(duì)列中取出隊(duì)列頭部的任務(wù),如果有就交給并發(fā)線程池去執(zhí)行 
  if ((mActive = mTasks.poll()) != null) { 
   THREAD_POOL_EXECUTOR.execute(mActive); 
  } 
 } 
}

public static final Executor THREAD_POOL_EXECUTOR 
  = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 
    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); 

在上面的代碼中,如果有任務(wù)執(zhí)行,那么SerialExecutor的execute方法會(huì)被調(diào)用,它的邏輯是把Runnable對(duì)象加入ArrayDeque隊(duì)列中,然后判斷mActivie是否為空。第一次執(zhí)行時(shí)mActive當(dāng)然為空,所以執(zhí)行scheduleNext,其實(shí)就是取出任務(wù)隊(duì)列中的第一個(gè)任務(wù)交給線程池(THREAD_POOL_EXECUTOR)執(zhí)行。加入mTask隊(duì)列的Runnable對(duì)象的run方法里最終一定會(huì)調(diào)用scheduleNext,那么又會(huì)從任務(wù)隊(duì)列中取出隊(duì)頭任務(wù)執(zhí)行。這樣便實(shí)現(xiàn)了單線程順序執(zhí)行任務(wù),所以在AsyncTask中默認(rèn)啟用的是單線程執(zhí)行,只有上一個(gè)任務(wù)執(zhí)行后才會(huì)執(zhí)行下一個(gè)任務(wù)。如果想要啟用多線程執(zhí)行任務(wù),可以直接調(diào)用 executeOnExecutor(Executor exec, Params... params),這里的Executor參數(shù)可以使用AsyncTask自帶的THREAD_POOL_EXECUTOR,也可以自己定義。

Handler
AsyncTask內(nèi)部用Handler傳遞消息,它的實(shí)現(xiàn)如下:

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; 
  } 
 } 
} 

如果消息類(lèi)型是任務(wù)執(zhí)行后的返回值(MESSAGE_POST_RESULT)將調(diào)用finish()方法:

private void finish(Result result) { 
 if (isCancelled()) { 
  onCancelled(result); 
 } else { 
  onPostExecute(result); 
 } 
 mStatus = Status.FINISHED; 
} 

從上面可以知道,如果任務(wù)取消了,將調(diào)用onCancelled,否則調(diào)用onPostExecute,所以一個(gè)AsyncTask任務(wù)如果取消了,那么onPostExecute將不會(huì)得到執(zhí)行。

如果消息類(lèi)型是執(zhí)行進(jìn)度(MESSAGE_POST_PROGRESS)將調(diào)用onProgressUpdate,這個(gè)方法默認(rèn)是空方法,我們可以根據(jù)自己的需要重寫(xiě)。

總結(jié)
AsyncTask的主要邏輯就如上面所分析的,總結(jié)幾個(gè)需要注意的地方:

  • AsyncTask的類(lèi)必須在UI線程加載(從4.1開(kāi)始系統(tǒng)會(huì)幫我們自動(dòng)完成)
  • AsyncTask對(duì)象必須在UI線程創(chuàng)建
  • execute方法必須在UI線程調(diào)用
  • 不要手動(dòng)調(diào)用onPreExecute()、doInBackground、onProgressUpdate方法
  • 一個(gè)任務(wù)只能被調(diào)用一次(第二次調(diào)用會(huì)拋出異常)

相關(guān)文章

  • Android中Split()字符串分割特殊用法案例詳解

    Android中Split()字符串分割特殊用法案例詳解

    本文通過(guò)案例的形式給大家詳細(xì)介紹了android中split()字符串分割特殊用法的知識(shí),非常不錯(cuò)具有參考借鑒價(jià)值,感興趣的朋友參考下
    2016-11-11
  • Android手勢(shì)密碼view學(xué)習(xí)筆記(二)

    Android手勢(shì)密碼view學(xué)習(xí)筆記(二)

    這篇文章主要為大家詳細(xì)介紹了Android手勢(shì)密碼view的第二篇學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 關(guān)于Android 6.0權(quán)限的動(dòng)態(tài)適配詳解

    關(guān)于Android 6.0權(quán)限的動(dòng)態(tài)適配詳解

    Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用戶體驗(yàn), 同時(shí)也為程序員帶來(lái)新的負(fù)擔(dān). 動(dòng)態(tài)權(quán)限管理就是這樣, 一方面讓用戶更加容易的控制自己的隱私, 一方面需要重新適配應(yīng)用權(quán)限,本文介紹了關(guān)于Android 6.0權(quán)限動(dòng)態(tài)適配的相關(guān)資料,需要的朋友可以參考下。
    2017-11-11
  • Android仿微信視屏懸浮窗效果

    Android仿微信視屏懸浮窗效果

    這篇文章主要為大家詳細(xì)介紹了Android仿微信視屏懸浮窗效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 快速解決進(jìn)入fragment時(shí)不能彈出軟件盤(pán)的問(wèn)題

    快速解決進(jìn)入fragment時(shí)不能彈出軟件盤(pán)的問(wèn)題

    下面小編就為大家?guī)?lái)一篇快速解決進(jìn)入fragment時(shí)不能彈出軟件盤(pán)的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • Android自定義View繪制的方法及過(guò)程(二)

    Android自定義View繪制的方法及過(guò)程(二)

    這篇文章主要解析了Android自定義View繪制的方法及過(guò)程,介紹了onSizeChanged、onDraw、onMeasure順序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android 之BottomsheetDialogFragment仿抖音評(píng)論底部彈出對(duì)話框效果(實(shí)例代碼)

    Android 之BottomsheetDialogFragment仿抖音評(píng)論底部彈出對(duì)話框效果(實(shí)例代碼)

    這篇文章主要介紹了Android 中之BottomsheetDialogFragment仿抖音評(píng)論底部彈出對(duì)話框效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Android仿微信滑動(dòng)彈出編輯、刪除菜單效果、增加下拉刷新功能

    Android仿微信滑動(dòng)彈出編輯、刪除菜單效果、增加下拉刷新功能

    這篇文章主要介紹了Android仿微信滑動(dòng)彈出編輯、刪除菜單效果、增加下拉刷新功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-01-01
  • Android中View繪制流程詳細(xì)介紹

    Android中View繪制流程詳細(xì)介紹

    這篇文章主要介紹了Android中View繪制流程詳細(xì)介紹,涉及創(chuàng)建ViewRoot并關(guān)聯(lián)View,ViewRoot等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Android?NDK開(kāi)發(fā)之FFmpeg視頻添加水印

    Android?NDK開(kāi)發(fā)之FFmpeg視頻添加水印

    這篇文章主要介紹了在Android?NDK開(kāi)發(fā)中如何通過(guò)FFmpeg為視頻添加水印,文中的示例代碼講解詳細(xì),對(duì)我們了解Android開(kāi)發(fā)有一定的幫助,感興趣的可以學(xué)習(xí)一下
    2021-12-12

最新評(píng)論

横山县| 镇赉县| 衡阳市| 鹿泉市| 海林市| 清丰县| 富源县| 马山县| 会宁县| 沙洋县| 紫阳县| 密山市| 故城县| 汉川市| 朔州市| 拉孜县| 许昌县| 河间市| 连平县| 衡南县| 南涧| 贡嘎县| 林甸县| 凤翔县| 禹州市| 房产| 新平| 乳山市| 肇州县| 通城县| 榆林市| 璧山县| 南通市| 南部县| 台东县| 司法| 阿图什市| 星子县| 雷州市| 习水县| 嘉兴市|