比較好的部落格:
https://blog.csdn.net/qq_30379689/article/details/53203556
https://blog.csdn.net/guolin_blog/article/details/11711405
AsyncTask是對Handler與線程池的封裝,目的也是實作線程間的通信,子線程執行耗時操作發送消息到主線程更新UI,使用線程池的主要原因是避免不必要的建立及銷毀線程的開銷
1. AsyncTask的使用方法
public class MainActivity extends Activity implements Button.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button bt_down = (Button) findViewById(R.id.button)
bt_down.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
URL url = new URL("http://blog.csdn.net/");
new MyAsyncTask().execute(url); //0. 執行execute開始執行異步任務
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
private class MyAsyncTask extends AsyncTask<URL, Integer, Long> { //AsyncTask是一個抽象類,Handler是一個普通的類
@Override
protected void onPreExecute() { //1. 主線程執行onPreExecute(執行異步任務前執行)
//異步任務開啟之前回調,在主線程中執行
super.onPreExecute();
}
@Override
protected Long doInBackground(URL... urls) { //2. 線程池執行doInBackground(執行異步任務)
//執行異步任務,線上程池中執行
long totalSize = 0;
int i = 0;
try {
while (i < 100) {
Thread.sleep(50);
i = i + 5;
publishProgress(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
totalSize = totalSize + i;
return totalSize;
}
@Override
protected void onProgressUpdate(Integer... progress) { //3. 執行doInBackground的過程中執行publishProgress,主線程回調執行onProgressUpdate
//當doInBackground中調用publishProgress時回調,在主線程中執行
pb_progress.setProgress(progress[0]);
}
@Override
protected void onPostExecute(Long result) { //4. 主線程執行onPostExecute(執行異步任務後執行)
//在異步任務執行之後回調,在主線程中執行
Toast.makeText(MainActivity.this, "下載下傳完成,結果是" + result, Toast.LENGTH_SHORT).show();
}
@Override
protected void onCancelled() { //5. 異步任務被取消時回調
//在異步任務被取消時回調
super.onCancelled();
}
}
}
AsyncTask的三個泛型參數:
a. Params:異步任務的參數,在執行AsyncTask時需要傳入的參數,可用于在背景任務中使用。
b. Progress:進度條相關,背景任務執行時,如果需要在界面上顯示目前的進度,則使用這裡指定的泛型作為進度機關。
c. Result:任務的執行結果,當任務執行完畢後,如果需要對結果進行傳回,則使用這裡指定的泛型作為傳回值類型。
參考:https://blog.csdn.net/guolin_blog/article/details/11711405
a. onPreExecute():在背景任務執行之前調用 //用于界面的初始化操作,比如顯示一個進度條對話框等。
b. doInBackground(Params…):在子線程中運作 //處理耗時任務,任務一旦執行完畢就可以通過return語句來将任務的執行結果result進行傳回
如果AsyncTask的第三個泛型參數指定的是void,就可以不傳回任務執行結果。注意,在這個方法中是不可以進行UI操作的,如果需要更新UI元素,比如說回報目前任務的執行進度,
可以調用publishProgress(Progress…)方法來完成。
c. onProgressUpdate(Progress…):當在doInBackground中調用了publishProgress(Progress…)方法後,這個方法就很快會被調用,方法中攜帶的參數就是在背景任務中傳遞過來的。
在這個方法中可以對UI進行操作,利用參數中的數值就可以對界面元素進行相應的更新。
d. onPostExecute(Result):在背景任務執行之後調用,當背景任務執行完畢并通過return語句将執行結果result傳回時,這個方法就很快會被調用。傳回的資料result會作為參數傳遞到此方法中,
可以利用傳回的資料來進行一些UI操作,比如說提醒任務執行的結果,以及關閉掉進度條對話框等。
AsyncTask用法總結:
首先定義一個繼承自AsyncTask的MyAsyncTask并複寫onPreExecute、doInBackground、onPostExecute方法
主線程執行個體化MyAsyncTask,并調用execute方法,會依次執行onPreExecute、doInBackground、onPostExecute方法
其中onPreExecute和onPostExecute在主線程中執行,doInBackground在子線程中執行,doInBackground在執行publishProgress時會回調到主線程執行onProgressUpdate重新整理UI
2. 源碼分析:new MyAsyncTask().execute(url);
2.1 分析new MyAsyncTask()
public abstract class AsyncTask<Params, Progress, Result> { //Params = URL, Progress = Integer, Result = Long
public AsyncTask() { //執行new MyAsyncTask()
this((Looper) null); ---------------------------
} |
public AsyncTask(@Nullable Looper callbackLooper) { <----------
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler() //并不是獲得主線程的Handler,而是獲得内部類AsyncTask.InternalHandler
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception { //複寫call()方法,執行call()時會執行doInBackground
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
...
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) { --------------------------
@Override |
protected void done() { |
try { |
postResultIfNotInvoked(get()); |
} |
} |
}; |
} |
} |
public class FutureTask<V> implements RunnableFuture<V> { <-----------------
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable; //FutureTask.callable = mWorker
this.state = NEW;
}
}
總結:
執行new MyAsyncTask()執行個體化一個AsyncTask,且AsyncTask.mFuture = new FutureTask(mWorker),且mWorker = new WorkerRunnable<Params, Result>()
在new WorkerRunnable()時會複寫call()方法,執行call()時會執行doInBackground
2.2 分析MyAsyncTask.execute(url);
frameworks\base\core\java\android\os\AsyncTask.java:
public abstract class AsyncTask<Params, Progress, Result> {
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, //exec = sDefaultExecutor = SERIAL_EXECUTOR = new SerialExecutor()
Params... params) { //params = new URL("http://blog.csdn.net/")
if (mStatus != Status.PENDING) { //隻有異步任務的狀态是PENDING時才可以往下執行
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("...");
case FINISHED:
throw new IllegalStateException("...");
}
}
mStatus = Status.RUNNING; //異步任務的狀态變為RUNNING,此時如果再一次使用execute執行異步任務時會抛出異常IllegalStateException
onPreExecute(); //重點:1. 主線程執行onPreExecute
mWorker.mParams = params;
exec.execute(mFuture); ------------------------------------------------------ //exec = new SerialExecutor(),mFuture = new FutureTask(mWorker),mWorker = new WorkerRunnable()
return this; | 且mWorker.mParams = new URL("http://blog.csdn.net/")
} |
|
||主線程建立子線程,并切換到子線程中執行run() |
\/ |
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(); -------------------------------------------- //r = mFuture = new FutureTask(mWorker),其中FutureTask.callable = mWorker
} finally { |
scheduleNext(); |
} |
} |
}); |
if (mActive == null) { |
scheduleNext(); |
} |
} |
protected synchronized void scheduleNext() { |
if ((mActive = mTasks.poll()) != null) { |
THREAD_POOL_EXECUTOR.execute(mActive); |
} |
} |
} |
} |
|
public class FutureTask<V> implements RunnableFuture<V> { |
public void run() { <-----------------------------------------------
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable; //c = FutureTask.callable = mWorker,其中mWorker = new WorkerRunnable()
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call(); ------------------------------------------------- //執行mWorker.call(),會回調doInBackground
ran = true; |
} catch (Throwable ex) { |
result = null; |
ran = false; |
setException(ex); |
} |
if (ran) |
set(result); |
} |
} finally { |
... |
} |
} |
} |
|
public abstract class AsyncTask<Params, Progress, Result> { |
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);
result = doInBackground(mParams); //重點:2. 子線程執行doInBackground
Binder.flushPendingCommands();
} catch (Throwable tr) {
...
} finally {
postResult(result); -------------------------
} |
return result; |
} |
}; |
} |
private Result postResult(Result result) { <----------------
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, ---------
new AsyncTaskResult<Result>(this, result)); |
message.sendToTarget(); -------------------------------------------------------------------------
return result; | |
} | |
private Handler getHandler() { <---------------------------------------------------| |
return mHandler; //mHandler = AsyncTask.InternalHandler | |
} | |
} | |
| |
分析mHandler | |
public abstract class AsyncTask<Params, Progress, Result> { | |
public AsyncTask(@Nullable Looper callbackLooper) { | |
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() | |
? getMainHandler() ------------------- | |
: new Handler(callbackLooper); | | |
} | | |
private static Handler getMainHandler() { <------ | |
synchronized (AsyncTask.class) { | |
if (sHandler == null) { | |
sHandler = new InternalHandler(Looper.getMainLooper()); --- | |
} | | |
return sHandler; | | |
} | | |
} | | |
private static class InternalHandler extends Handler { | | |
public InternalHandler(Looper looper) { <-------------------------- | |
super(looper); | |
} | |
@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; | |
} | |
} | |
} | |
} | |
| |
| |
| |
public class Handler { | |
public final Message obtainMessage(int what, Object obj){ <----------------------- |
return Message.obtain(this, what, obj); ---------------------- |
} | |
} | |
| |
public final class Message implements Parcelable { | |
public static Message obtain(Handler h, int what, Object obj) { <----- |
Message m = obtain(); |
m.target = h; //Message.target = mHandler = AsyncTask.InternalHandler
m.callback = callback; //Message.callback = MESSAGE_POST_RESULT |
m.obj = obj; //Message.obj = new AsyncTaskResult<Result>(this, result)),其中result = doInBackground(mParams);
return m; |
} |
public void sendToTarget() { <--------------------------------------------------------------------
target.sendMessage(this); --------------------------------------------------
} |
} |
|
|
||使用Handler機制,子線程發送一個Message切換到主線程 |
\/ |
|
public abstract class AsyncTask<Params, Progress, Result> { |
private static class InternalHandler extends Handler { |
public InternalHandler(Looper looper) { |
super(looper); |
} |
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) |
@Override |
public void handleMessage(Message msg) { <---------------------------------
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; //result = new AsyncTaskResult<Result>(this, result)),其中this = new MyAsyncTask(),result = doInBackground(mParams);
switch (msg.what) { |
case MESSAGE_POST_RESULT: |
// There is only one result |
result.mTask.finish(result.mData[0]); ---------------------- //result.mTask = new MyAsyncTask() |
break; | result.mData[0] = result = doInBackground(mParams);
case MESSAGE_POST_PROGRESS: | |
result.mTask.onProgressUpdate(result.mData); | |
break; | |
} | |
} | |
} | |
private void finish(Result result) { <----------------------------------------- |
if (isCancelled()) { //如果目前任務已經被取消掉了,就會調用onCancelled()方法 |
onCancelled(result); |
} else { |
onPostExecute(result); //重點:3. 主線程執行onPostExecute,result為執行doInBackground的傳回值 |
} |
mStatus = Status.FINISHED; //任務執行完畢,狀态設定為FINISHED |
} |
} |
|
public abstract class AsyncTask<Params, Progress, Result> { |
private static class AsyncTaskResult<Data> { <------------------------------------------------------------------
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task; //AsyncTaskResult.mTask = MyAsyncTask
mData = data; //AsyncTaskResult.mData = result = doInBackground(mParams);
}
}
}
若在doInBackground中調用了publishProgress(Progress...)方法,會調用onProgressUpdate(Progress...),過程分析如下:
public abstract class AsyncTask<Params, Progress, Result> {
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS, ------------------
new AsyncTaskResult<Progress>(this, values)).sendToTarget(); -----|-------------------------
} | |
} | |
} | |
public class Handler { | |
public final Message obtainMessage(int what, Object obj){ <--------------- |
return Message.obtain(this, what, obj); ------------------------- |
} | |
} | |
public final class Message implements Parcelable { | |
public static Message obtain(Handler h, int what, Object obj) { <---- |
Message m = obtain(); |
m.target = h; //Message.target = mHandler = AsyncTask.InternalHandler |
m.what = what; //Message.what = MESSAGE_POST_PROGRESS |
m.obj = obj; //Message.obj = new AsyncTaskResult<Progress>(this, values)).sendToTarget(); |
return m; |
} |
public void sendToTarget() { <------------------------------------------------------------------------
target.sendMessage(this);
}
}
||使用Handler機制,子線程發送一個Message切換到主線程
\/
public abstract class AsyncTask<Params, Progress, Result> {
private static class InternalHandler extends Handler {
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); //重點:4. 主線程執行onProgressUpdate,result.mTask = new MyAsyncTask()
break;
}
}
}
}
在定義MyAsyncTask時複寫onCancelled(),在哪裡被調用?
public abstract class AsyncTask<Params, Progress, Result> {
private void finish(Result result) {
if (isCancelled()) { //如果目前任務已經被取消掉了,就會調用onCancelled()方法
onCancelled(result); //重點:5. 主線程執行onCancelled,result為執行doInBackground的傳回值
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
}
3. 幾個問題
3.1 如果多次執行MyAsyncTask.execute()會重複執行異步任務嗎?
不會,當第一次執行MyAsyncTask.execute()時MyAsyncTask.mStatus = Status.PENDING,不會抛出異常,且将狀态改變為MyAsyncTask.mStatus = Status.RUNNING
當第二次執行MyAsyncTask.execute()時MyAsyncTask.mStatus != Status.PENDING,會抛出異常,不會往下執行,是以不會多次執行異步任務
3.2 MyAsyncTask.execute()時依次執行onPreExecute、doInBackground、onPostExecute方法,且onPreExecute和onPostExecute在主線程中執行,doInBackground在子線程中執行那麼從onPreExecute到doInBackground是如何從主線程切換到子線程?從doInBackground到onPostExecute是如何從子線程切換到主線程?
執行MyAsyncTask.execute()時會在主線程執行onPreExecute,接着會使用SerialExecutor建立子線程,并在子線程中執行doInBackground,最終會執行postResult
使用Handler機制發送一個Message切換到主線程執行onProgressUpdate重新整理UI
AsyncTask原理總結:
執行MyAsyncTask.execute()時會在主線程執行onPreExecute,接着會使用SerialExecutor建立子線程,并在子線程中執行doInBackground,最終會執行postResult将doInBackground的
執行結果result儲存到AsyncTaskResult.mData中,将AsyncTaskResult儲存到Message.obj中,使用Handler機制發送一個Message切換到主線程,取出result,判斷目前異步任務是否已經被取消,
如果已經被取消則會調用onCancelled()方法,如果沒有被取消則會調用onPostExecute
當在執行doInBackground的過程中如果執行publishProgress時會使用Handler機制發送一個Message切換到主線程執行onProgressUpdate重新整理UI