前言:?
在Android應用程序開發中,異步操作是非常常見的需求。比如,我們可能需要在后臺線程中執行網絡請求、數據庫操作或者其他耗時的任務,而不阻塞UI線程。為了實現這些異步操作,Android提供了多種方式,其中之一就是使用AsyncTask類。
1.什么是AsyncTask?
? ? ?AsyncTask是一種輕量級的異步任務類,它可以在線程池中執行后臺任務,然后把執行的進度和最終的結果傳遞給主線程并在主線程中更新UI。(兩個線程池+Handler)
2.介紹AsyncTask類的泛型參數和核心方法
AsyncTask是一個抽象的泛型類,它提供了Params,Progress和Result這三個泛型參數。
public abstract class AsyncTask<Params, Progress, Result>
其中,
- 🟨Params表示參數的類型
- 🟨Progress表示后臺任務的執行進度和類型
- 🟨Result表示后臺任務的返回結果
AsyncTask類提供了四個核心方法(按照執行順序介紹):
1??onPreExecute():在主線程中執行,用于準備工作。
2??doInBackground(Params...params):在線程池中執行,用于執行異步任務。在此方法中可以通過publishProgress方法來更新任務的進度,publishProgress方法調用onProgressUpdate方法。
3??onProgressUpdate(Progress...values):在主線程中執行,當后臺任務的執行進程發送變化時此方法會被調用。
4??onPostExecute(Result result):在主線程中執行,在異步任務執行之后,此方法會被調用。
AsyncTask還提供了onCancelled()方法,它同樣在主線程中執行,當異步任務被取消時,onCancelled會被調用,這個時候,onPostExecute則不會被調用。
3.如何使用AsyncTask?
使用AsyncTask的步驟:
🔶步驟一:繼承AsyncTask類,并實現它的幾個回調方法,比如doInBackground()方法用來執行后臺任務,onPostExecute()方法用來更新UI。
🔶步驟二:在UI線程中創建AsyncTask的實例,并調用execute()方法來啟動異步操作。
示例:
在Activity中,創建一個子類來繼承AsyncTask,完成以下任務:
1.展示ProgressDialog
2.發送網絡請求
3.關閉ProgressDialog
代碼如下:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new AsyncTask_test().execute("");}
?public static ProgressDialog dialog;public class AsyncTask_test extends AsyncTask<String,Integer,Long> {@Overrideprotected void onPreExecute() {dialog=ProgressDialog.show(MainActivity.this,"", "努力加載中");}
?@Overrideprotected Long doInBackground(String... strings) {OkHttpClient okHttpClient = new OkHttpClient();Request request=new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();Response response= null;try {response = okHttpClient.newCall(request).execute();if(!response.isSuccessful()){Log.e("xxx","網絡請求失敗"+response);}String responsedata=response.body().string();if(responsedata!=null){Log.e("xxx","輸出:"+responsedata);}} catch (IOException e) {Log.e("xxx","報錯"+e);throw new RuntimeException(e);}
?return null;}
?@Overrideprotected void onPostExecute(Long aLong) {if(dialog!=null){dialog.dismiss();}super.onPostExecute(aLong);}}
}
AsyncTask在使用時的注意事項:
🟠AsyncTask的對象必須在主線程中創建。(原因:AsyncTask的handler對象是靜態的,Handler對象要切換到主線程,由于靜態成員在類加載時就被初始化,因此AsyncTask必須在主線程中加載)
🟠execute方法必須在UI線程調用。
🟠不要在線程中直接調用onPreExecute()、onPostExecute、doInBackground和onProgressUpdate方法。
🟠一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常。
4.AsyncTask的工作原理
工作原理:
??當asyncTask執行execute()方法的時候,會先調用onPreExecute()方法。
??然后調用SERIAL_EXECUTOR的execute(mFuture),把任務加入到隊列的尾部等待執行。
??執行的時候調用THREAD_POOL_EXECUTOR的execute(mFuture)方法。
??mFuture調用mWorker的call()方法,在call()方法中調用了dolnBackground()方法,并在最后調用了postResult()方法。
??postResult()方法也就是通過Handler發送消息給主線程,在主線程中調用AsyncTask的finish()方法,來決定是調用onCancelled()還是onPostExecute()方法。
源碼解析:
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params); }@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)");}} ?mStatus = Status.RUNNING; ?onPreExecute(); ?mWorker.mParams = params;exec.execute(mFuture); ?return this;}
其中,sDefaultExecutor是一個串行的線程池,一個進程中所有的AsyncTask全部在這個串行的線程池中排隊執行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先執行,然后線程池開始執行,下面是線程池的執行過程:
? public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;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);}}}
當一個AsyncTask任務執行完后,AsyncTask會調用scheduleNext()方法繼續執行下一個任務直到所有任務被執行為止,總的來說,默認情況下,AsyncTask是串行執行的。
AsyncTask中有兩個線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個Handle:
SerialExecutor:用于任務的排隊
THREAD_POOL_EXECUTOR:用于真正地執行任務
Handler:用于將執行環境從線程池切換到主線程
在AsyncTask的構造方法中有如下一段代碼,由于FutureTask的run方法會調用mWorker的call方法,因此mWorker的call方法最終會在線程池中執行。
public AsyncTask(@Nullable Looper callbackLooper) {mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()? getMainHandler(): new Handler(callbackLooper); ?mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams);Binder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}return result;}}; ?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);}}};} ?
在mWorker的call方法中,首先將mTaskInvoked設為true,表示當前任務已經被調用過了,然后執行AsyncTask的doInBackground方法,接著將返回值傳遞給postResult方法,它的實現如下:
private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result; }
在上面代碼中,postResult方法會通過Handler對象發送一個MESSAGE_POST_RESULT的消息,這個Handler對象的定義如下:
getHandler()獲取Handler對象
private Handler getHandler() {return mHandler; }
賦值mHandler
private final Handler mHandler; public AsyncTask(@Nullable Looper callbackLooper) {mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()? getMainHandler(): new Handler(callbackLooper);...}
(1)如果callbackLooper == null,就getMainHandler()
private static Handler getMainHandler() {synchronized (AsyncTask.class) {if (sHandler == null) {sHandler = new InternalHandler(Looper.getMainLooper());}return sHandler;} }
(2)如果callbackLooper == Looper.getMainLooper(),就new Handler(callbackLooper)
public Handler(@NonNull Looper looper) {this(looper, null, false); }
Handler對象收到MESSAGE_POST_RESULT這個消息后會調用AsyncTask的finish方法。
private void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {onPostExecute(result);}mStatus = Status.FINISHED; }
如果AsyncTask被取消執行了,那么就調用onCancelled方法,否則就會調用onPostExecute方法,就可以看到doInBackground的返回結果會傳遞給onPostExecute方法,到這里AsyncTask的整個工作過程就分析完畢了。
總結
通過本篇博客,我們了解了AsyncTask的工作原理和如何在Android應用程序中使用它來進行異步操作。AsyncTask提供了一種簡單而強大的方式來管理異步任務,并在UI線程中更新UI,是Android開發中不可或缺的工具之一。希望本篇博客能幫助你更好地理解和使用AsyncTask。