日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

android AsyncTask 的分析与运用

發(fā)布時間:2025/6/15 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android AsyncTask 的分析与运用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

線程

在Android當(dāng)中,通常將線程分為兩種,一種叫做Main Thread,除了Main Thread之外的線程都可稱為Worker Thread。

當(dāng)一個應(yīng)用程序運行的時候,Android操作系統(tǒng)就會給該應(yīng)用程序啟動一個線程,這個線程就是我們的Main Thread,這個線程非常的重要,它主要用來加載我們的UI界面,完成系統(tǒng)和我們用戶之間的交互,并將交互后的結(jié)果又展示給我們用戶,所以Main Thread又被稱為UI Thread。

Android系統(tǒng)默認(rèn)不會給我們的應(yīng)用程序組件創(chuàng)建一個額外的線程,所有的這些組件默認(rèn)都是在同一個線程中運行。然而,某些時候當(dāng)我們的應(yīng)用程序需要完成一個耗時的操作的時候,例如訪問網(wǎng)絡(luò)或者是對數(shù)據(jù)庫進(jìn)行查詢時,此時我們的UI Thread就會被阻塞。例如,當(dāng)我們點擊一個Button,然后希望其從網(wǎng)絡(luò)中獲取一些數(shù)據(jù),如果此操作在UI Thread當(dāng)中完成的話,當(dāng)我們點擊Button的時候,UI線程就會處于阻塞的狀態(tài),此時,我們的系統(tǒng)不會調(diào)度任何其它的事件,更糟糕的是,當(dāng)我們的整個現(xiàn)場如果阻塞時間超過5秒鐘(官方是這樣說的),這個時候就會出現(xiàn) ANR (Application Not Responding)的現(xiàn)象,此時,應(yīng)用程序會彈出一個框,讓用戶選擇是否退出該程序。對于Android開發(fā)來說,出現(xiàn)ANR的現(xiàn)象是絕對不能被允許的。

另外,由于我們的Android UI控件是線程不安全的,所以我們不能在UI Thread之外的線程當(dāng)中對我們的UI控件進(jìn)行操作。因此在Android的多線程編程當(dāng)中,我們有兩條非常重要的原則必須要遵守:

  • 絕對不能在UI Thread當(dāng)中進(jìn)行耗時的操作,不能阻塞我們的UI Thread
  • 不能在UI Thread之外的線程當(dāng)中操縱我們的UI元素
  • 線程間通信

    既然在Android當(dāng)中有兩條重要的原則要遵守,那么我們可能就有疑問了?我們既不能在主線程當(dāng)中處理耗時的操作,又不能在工作線程中來訪問我們的UI控件,那么我們比如從網(wǎng)絡(luò)中要下載一張圖片,又怎么能將其更新到UI控件上呢?這就關(guān)系到了我們的主線程和工作線程之間的通信問題了。在Android當(dāng)中,提供了兩種方式來解決線程直接的通信問題,一種是通過Handler的機制( 可以閱讀-關(guān)于Handler的理解),還有一種就是今天要詳細(xì)講解的 AsyncTask 機制。

    AsyncTask

    關(guān)于AsyncTask的解釋,Google上面是這樣說的:

    AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

    An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.

    大概意思就是說“它使創(chuàng)建異步任務(wù)變得更加簡單,不再需要編寫任務(wù)線程和Handler實例即可完成相同的任務(wù)。一個異步任務(wù)通常是在后臺運行的計算等然后將結(jié)果發(fā)送到UI主線程中去。通常情況下,異步任務(wù)被定義為3種通用類型,分別為:參數(shù)、過程以及結(jié)果和4個步驟,分別為“onPreExecute、doInBackground、onProgressUpdate、onPostExecute””這就是關(guān)于異步任務(wù)的大概說明。

    怎么來理解AsyncTask呢?通俗一點來說,AsyncTask就相當(dāng)于Android給我們提供了一個多線程編程的一個框架,其介于Thread和Handler之間,我們?nèi)绻x一個AsyncTask,就需要定義一個類來繼承AsyncTask這個抽象類,并實現(xiàn)其唯一的一個 doInBackgroud 抽象方法。要掌握AsyncTask,我們就必須要一個概念,總結(jié)起來就是: 3個泛型,4個步驟。

    3個泛型

    3個泛型指的是什么呢?我們來看看AsyncTask這個抽象類的定義,當(dāng)我們定義一個類來繼承AsyncTask這個類的時候,我們需要為其指定3個泛型參數(shù):

    public abstract class AsyncTask<Params, Progress, Result>復(fù)制代碼

    Params: 這個泛型指定的是我們傳遞給異步任務(wù)執(zhí)行時的參數(shù)的類型
    Progress: 這個泛型指定的是我們的異步任務(wù)在執(zhí)行的時候?qū)?zhí)行的進(jìn)度返回給UI線程的參數(shù)的類型
    Result: 這個泛型指定的異步任務(wù)執(zhí)行完后返回給UI線程的結(jié)果的類型

    4個步驟

    4個步驟:當(dāng)我們執(zhí)行一個異步任務(wù)的時候,其需要按照下面的4個步驟分別執(zhí)行:

    1、onPreExecute():
    這個方法是在執(zhí)行異步任務(wù)之前的時候執(zhí)行,并且是在UI Thread當(dāng)中執(zhí)行的,通常我們在這個方法里做一些UI控件的初始化的操作,例如彈出要給ProgressDialog。

    2、doInBackground(Params... params):
    在onPreExecute()方法執(zhí)行完之后,會馬上執(zhí)行這個方法,這個方法就是來處理異步任務(wù)的方法,Android操作系統(tǒng)會在后臺的線程池當(dāng)中開啟一個worker thread來執(zhí)行我們的這個方法,所以這個方法是在worker thread當(dāng)中執(zhí)行的,這個方法執(zhí)行完之后就可以將我們的執(zhí)行結(jié)果發(fā)送給我們的最后一個 onPostExecute 方法,在這個方法里,我們可以從網(wǎng)絡(luò)當(dāng)中獲取數(shù)據(jù)等一些耗時的操作。

    3、onProgressUpdate(Progess... values):
    這個方法也是在UI Thread當(dāng)中執(zhí)行的,我們在異步任務(wù)執(zhí)行的時候,有時候需要將執(zhí)行的進(jìn)度返回給我們的UI界面,例如下載一張網(wǎng)絡(luò)圖片,我們需要時刻顯示其下載的進(jìn)度,就可以使用這個方法來更新我們的進(jìn)度。這個方法在調(diào)用之前,我們需要在 doInBackground 方法中調(diào)用一個 publishProgress(Progress) 的方法來將我們的進(jìn)度時時刻刻傳遞給 onProgressUpdate 方法來更新。

    4、onPostExecute(Result... result):
    當(dāng)我們的異步任務(wù)執(zhí)行完之后,就會將結(jié)果返回給這個方法,這個方法也是在UI Thread當(dāng)中調(diào)用的,我們可以將返回的結(jié)果顯示在UI控件上。

    為什么我們的AsyncTask抽象類只有一個 doInBackground 的抽象方法呢??原因是,我們?nèi)绻鲆粋€異步任務(wù),我們必須要為其開辟一個新的Thread,讓其完成一些操作,而在完成這個異步任務(wù)時,我可能并不需要彈出要給ProgressDialog,我并不需要隨時更新我的ProgressDialog的進(jìn)度條,我也并不需要將結(jié)果更新給我們的UI界面,所以除了 doInBackground 方法之外的三個方法,都不是必須有的,因此我們必須要實現(xiàn)的方法是 doInBackground 方法。

    實例演示

    接下來我們通過下載一張網(wǎng)絡(luò)圖片進(jìn)行演示對于AsyncTask的使用。首先來看下效果:

    其次,我們來了解一些相關(guān)代碼。其實下載的代碼原理很簡單,就是通過流的方式轉(zhuǎn)為字節(jié)數(shù)組,然后再轉(zhuǎn)化為Bitmap而已。

    //進(jìn)度框顯示progressDialog = new ProgressDialog(MainActivity.this);progressDialog.setTitle("提示信息");progressDialog.setMessage("正在下載中,請稍后......");// 設(shè)置setCancelable(false); 表示我們不能取消這個彈出框,等下載完成之后再讓彈出框消失progressDialog.setCancelable(false);// 設(shè)置ProgressDialog樣式為水平的樣式progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//下載類 public class MyAsyncTask extends AsyncTask<String, Integer, Bitmap> {@Overrideprotected void onPreExecute() {super.onPreExecute();// 在onPreExecute()中我們讓ProgressDialog顯示出來progressDialog.show();}@Overrideprotected Bitmap doInBackground(String... params) {Bitmap bitmap = null;try {URL url = new URL(params[0]);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setRequestMethod("GET");InputStream inputStream = conn.getInputStream();if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {int fileLength = conn.getContentLength();ByteArrayOutputStream outStread = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length = 0;long total = 0;while ((length = inputStream.read(buffer)) != -1) {outStread.write(buffer, 0, length);total += length;if (fileLength > 0) {publishProgress((int) (total * 100 / fileLength));}}outStread.close();inputStream.close();byte[] data = outStread.toByteArray();if (data != null) {bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);} else {Toast.makeText(MainActivity.this, "Image error!", Toast.LENGTH_LONG).show();}return bitmap;}} catch (Exception e) {e.printStackTrace();}return null;}@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);// 更新ProgressDialog的進(jìn)度條progressDialog.setProgress(values[0]);}@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);imageView.setImageBitmap(bitmap);try {saveFile(bitmap, "netpic.jpg");} catch (IOException e) {e.printStackTrace();}progressDialog.dismiss();}}//在UI主線程中執(zhí)行下載程序 String picUrl = "http://img3.imgtn.bdimg.com/it/u=2437337628,1430863508&fm=214&gp=0.jpg";new MyAsyncTask().execute(picUrl);復(fù)制代碼

    詳細(xì)代碼請查看github-easy-net封裝學(xué)習(xí)基本的網(wǎng)絡(luò)請求庫


    到這里基本上就結(jié)束了。這就是簡單的運用AsyncTask進(jìn)行UI線程和Work線程進(jìn)行通信的基本方式。接下來我們就源碼進(jìn)行深入的研究關(guān)于AsyncTask的相關(guān)內(nèi)容。

    源碼解讀(基于API25)

    首先我們從異步任務(wù)的起點execute開始分析:

    //<p>This method must be invoked on the UI thread. //必須在UI主線程中調(diào)用該方法。 @MainThreadpublic final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);}//跳轉(zhuǎn)到executeOnExecutor方法 @MainThreadpublic 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)");}}//設(shè)置當(dāng)前AsyncTask的狀態(tài)為RUNNINGmStatus = Status.RUNNING;//還是在UI主線程,這個時候可以進(jìn)行一些初始化操作onPreExecute();mWorker.mParams = params;exec.execute(mFuture);return this;}復(fù)制代碼

    代碼比較簡單,其中出現(xiàn)了mWork和mFuture變量,接下來我們跟蹤這兩個變量進(jìn)行研究。

    1、對于mWork變量

    private final WorkerRunnable<Params, Result> mWorker;private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {Params[] mParams;} //可以看到是Callable的子類,且包含一個mParams用于保存我們傳入的參數(shù),接下來看看 mWork的初始化操作 //這是在AsyncTask的構(gòu)造函數(shù)中進(jìn)行初始化的 mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {//設(shè)置為true,下面要用到mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection unchecked //這就是我們使用到的4個方法中的一個,獲取處理結(jié)果result = doInBackground(mParams);Binder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {//發(fā)送執(zhí)行結(jié)果postResult(result);}return result;}};復(fù)制代碼

    從上面源碼我們可以分析出mWork在AsyncTask的構(gòu)造函數(shù)中進(jìn)行初始化,然后實現(xiàn)CallBack的call方法,進(jìn)行一些設(shè)置,然后調(diào)用doInBackground方法,最后執(zhí)行postResult(result)進(jìn)行結(jié)果處理,接下來我們繼續(xù)分析postResult(result)方法。

    private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}復(fù)制代碼

    我們看到了熟悉的異步消息處理,Handler和Message,發(fā)送一個消息,

    msg.what=MESSAGE_POST_RESULT; msg.obj=new AsyncTaskResult<Result>(this, result);復(fù)制代碼

    從上面的代碼我們可以知道,既然handler已經(jīng)發(fā)送出了消息的話,,那么肯定會存在一個Handler,并在某處進(jìn)行消息的處理,我們來繼續(xù)尋找一下這些內(nèi)容:

    //找到相關(guān)的Handler private static Handler getHandler() {synchronized (AsyncTask.class) {if (sHandler == null) {sHandler = new InternalHandler();}return sHandler;}}//消息處理 private static class InternalHandler extends Handler {public InternalHandler() {super(Looper.getMainLooper());}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate(result.mData);break;}}}//消息處理完之后,設(shè)定狀態(tài)為finishedprivate void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {//執(zhí)行4個方法中的最后一步,處理結(jié)果onPostExecute(result);}//設(shè)置最后的狀態(tài)為結(jié)束finishedmStatus = Status.FINISHED;}復(fù)制代碼

    2、對于mFuture變量

    //申明變量 private final FutureTask<Result> mFuture;//在AsyncTask的構(gòu)造函數(shù)中進(jìn)行變量的初始化 mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected void done() {try {postResultIfNotInvoked(get());} catch (InterruptedException e) {android.util.Log.w(LOG_TAG, e);} catch (ExecutionException e) {throw new RuntimeException("An error occurred while executing doInBackground()",e.getCause());} catch (CancellationException e) {postResultIfNotInvoked(null);}}};//查看postResultIfNotInvoked方法,參數(shù)是get(),get()表示獲取mWorker的call的返回值,即Result。private void postResultIfNotInvoked(Result result) {final boolean wasTaskInvoked = mTaskInvoked.get();if (!wasTaskInvoked) {postResult(result);}}//注意上面的mWork初始化時設(shè)置的變量值mTaskInvoked.set(true),所以判斷中一般都是wasTaskInvoked=true,所以基本不會執(zhí)行復(fù)制代碼

    分析完了mWork和mFuture這兩個變量,我們接著分析下面的代碼:

    exec.execute(mFuture);

    這個exec其實就是sDefaultExecutor,那么這個sDefaultExecutor是什么東西呢?

    //sDefaultExecutor的定義 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//繼續(xù)跟蹤SERIAL_EXECUTOR public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//SerialExecutor的定義 private static class SerialExecutor implements Executor {//維護(hù)一個數(shù)組隊列final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();Runnable mActive;//執(zhí)行內(nèi)容public synchronized void execute(final Runnable r) {//在隊列的尾部插入一個任務(wù)taskmTasks.offer(new Runnable() {public void run() {try {r.run();} finally {scheduleNext();}}});if (mActive == null) {scheduleNext();}}protected synchronized void scheduleNext() {//取出隊首的任務(wù)開始執(zhí)行if ((mActive = mTasks.poll()) != null) {//開始執(zhí)行任務(wù)THREAD_POOL_EXECUTOR.execute(mActive);}}}復(fù)制代碼

    那么這個THREAD_POOL_EXECUTOR又是什么東西呢?接著分析這個變量:

    /*** An {@link Executor} that can be used to execute tasks in parallel.*/public static final Executor THREAD_POOL_EXECUTOR;//線程池配置static {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,sPoolWorkQueue, sThreadFactory);threadPoolExecutor.allowCoreThreadTimeOut(true);THREAD_POOL_EXECUTOR = threadPoolExecutor;}//變量設(shè)置private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();// We want at least 2 threads and at most 4 threads in the core pool,// preferring to have 1 less than the CPU count to avoid saturating// the CPU with background workprivate static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE_SECONDS = 30;復(fù)制代碼

    以上就是過程分析,接下來我們來進(jìn)一步總結(jié)說明具體的流程。

    首先設(shè)置當(dāng)前AsyncTask的狀態(tài)為RUNNING,然后執(zhí)行了onPreExecute(),當(dāng)前依然在UI線程,所以我們可以在其中做一些準(zhǔn)備工作。其次將我們傳入的參數(shù)賦值給了mWorker.mParams ,mWorker為一個Callable的子類,且在內(nèi)部的call()方法中,調(diào)用了doInBackground(mParams),然后得到的返回值作為postResult的參數(shù)進(jìn)行執(zhí)行;postResult中通過sHandler發(fā)送消息,最終sHandler的handleMessage中完成onPostExecute的調(diào)用。最后執(zhí)行exec.execute(mFuture),mFuture為真正的執(zhí)行任務(wù)的單元,將mWorker進(jìn)行封裝,然后由sDefaultExecutor交給線程池進(jìn)行執(zhí)行。

    這里面我們涉及到了4個方法中的三個,那么還有一個方法:

    //更新進(jìn)度 @Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);progressDialog.setProgress(values[0]);}復(fù)制代碼

    那么這個方法是什么時候調(diào)用的的呢?我們在使用AsyncTask中的第三個方法doInBackground時在里面我們調(diào)用了一個傳遞進(jìn)度的方法 publishProgress(int progress),我們進(jìn)入到該方法中查看一下:

    //工作線程中執(zhí)行該方法 @WorkerThreadprotected final void publishProgress(Progress... values) {if (!isCancelled()) {//通過Handler和Message異步消息機制進(jìn)行UI線程和Work線程通信getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();}}復(fù)制代碼

    publishProgress方法其實就是發(fā)送一個消息,

    msg.what=MESSAGE_POST_PROGRESS//消息類型 msg.obj=new AsyncTaskResult<Progress>(this, values)//進(jìn)度//處理消息 private static class InternalHandler extends Handler {public InternalHandler() {super(Looper.getMainLooper());}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS://處理進(jìn)度消息//調(diào)用onProgressUpdate方法顯示進(jìn)度result.mTask.onProgressUpdate(result.mData);break;}}}復(fù)制代碼

    這就很明朗了,四個方法都調(diào)用到了。以上便是AsyncTask所有的執(zhí)行流程,通過源碼分析可得AsyncTask的內(nèi)部也是使用Handler+Message的方式進(jìn)行消息傳遞和處理的。

    關(guān)于AsyncTask的內(nèi)幕

    1、深入理解AsyncTask的內(nèi)幕,線程池引發(fā)的重大問題

    注意

    Android6.0 谷歌把HttpClient相關(guān)的類移除了,所以如果繼續(xù)使用的話,需要添加相關(guān)的jar包。

    1、對于AndroidStudio的添加方法是:

    在相應(yīng)的module下的build.gradle中加入: android {useLibrary 'org.apache.http.legacy' }復(fù)制代碼

    2、對于Eclipse的添加方法是:

    libs中加入 org.apache.http.legacy.jar 上面的jar包在:**\android-sdk-windows\platforms\android-23\optional下(需要下載android 6.0的SDK)復(fù)制代碼

    參考鏈接

    1、http://www.cnblogs.com/xiaoluo501395377/p/3430542.html

    2、http://blog.csdn.net/liuhe688/article/details/6532519

    3、http://blog.csdn.net/lmj623565791/article/details/38614699

    總結(jié)

    以上是生活随笔為你收集整理的android AsyncTask 的分析与运用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。