天天看點

Android系統線程間通信方式之AsyncTask機制

比較好的部落格:

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