AsyncTask多任務執行

通過上篇博客對AsyncTask源碼進行分析之後,我們對AsyncTask的任務執行有了一個大致瞭解,但是在那篇博客中我有一個

問題還沒有分析到,那就是線程執行體SerialExecutor類,下面我們來看一下SerialExecutor類的源碼。

    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();//真正執行Callable中run方法的地方
                    } finally {
                        scheduleNext();//等待線程池中的任務執行完畢後,再往線程池中添加任務
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }//第一次被執行後,以後這段代碼都不會被執行了。
        }
        //下面的方法實現的效果是:從隊列首部取出任務並刪除,然後將取出的任務放入到線程池中。
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);//將任務添加到線程池中
            }
        }
        //上面代碼實現了單一線程池的效果,也就是線程池中同一時刻只有一個任務在執行。
    }

當我們調用execute方法時,通過上面的源碼我們可以看到,execute方法是帶阻塞的,如果我們添加多個任務時,第一調用execute時,由於mActive

爲空,所以將任務放入線程池中,如果第二次調用時,由於mActive不爲空了,所以只是將任務添加到隊列中去了,那麼這些後來添加的任務怎樣才

能放入線程池呢?我們看到在mTask添加匿名Runnable對象時,在其run方法中調用任務執行體r.run之後,最終會調用scheduleNext()方法,也就是

等到任務的執行體,執行完畢以後,纔會向線程池中添加下一個任務,這樣就實現了單一線程池的效果。

瞭解了上面的這些東西以後,我在創建AsyncTask對象後,調用其執行方法時,會發現有三個可以進行選擇。下面我們就來分析這三個方法的不同

我們實現AsyncTask後,知道那些異步,耗時,網絡的操作要放在doInBackground中去執行,但是瞭解了上面的東西之後,我們可以知道,其實

這些東西也不必放到doInBackground去執行,我們可以自定義Runnable接口,然後將其通過execute(runnable)方法,將其放入線程池中。

execute(),這個方法是將doInBackground的執行體放入到線程池中,而execute(runnable)則會將自定義的執行體放入線程池中,現在我們來模擬

執行多個任務時,會有什麼情況,還是使用上篇博客的那個例子

public class AsynActivity extends Activity implements OnClickListener{
	Button btn;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_asyn);
		
		btn = (Button)findViewById(R.id.asyn);
		btn.setOnClickListener(this);
	}	
	@Override
	public void onClick(View view) {
		TestAsyn asyn = new TestAsyn();			
		asyn.execute();
		TestAsyn.execute(new Task("任務二"));
		TestAsyn.execute(new Task("任務三"));
		TestAsyn.execute(new Task("任務四"));
		TestAsyn.execute(new Task("任務五"));
	}
	class Task implements Runnable{
		String str;
		public Task(String str){
			this.str = str;
		}
		@Override
		public void run() {
			Log.i("task", "任務"+str);
		}
	}
	 
	class TestAsyn extends AsyncTask<Void, Void, Result>{	
		@Override
		protected void onPreExecute() {
			Log.i("TestAsyn", "onPreExecute");
			super.onPreExecute();
		}
		
		@Override
		protected Result doInBackground(Void... params) {
			Log.i("TestAsyn", "doInBackground");			
			//cancel(true);
			//publishProgress(params);
			return null;
		}
		
		@Override
		protected void onPostExecute(Result result) {
			Log.i("TestAsyn", "onPostExecute");
			super.onPostExecute(result);
		}		
		@Override
		protected void onProgressUpdate(Void... values) {
			Log.i("TestAsyn", "onProgressUpdate");
			super.onProgressUpdate(values);
		}	
		@Override
		protected void onCancelled() {
			Log.i("TestAsyn", "onCancelled");
			super.onCancelled();
		}	
		@Override
		protected void onCancelled(Result result) {
			Log.i("TestAsyn", "onCancelled");
			super.onCancelled(result);
		}
	}
}


執行結果:




從執行結果中我們可以看出,每次運行的結果是不同的,但是有一點是確定的,那就是任務添加的順序就是結果的輸出順序,這也印證了

之前對源碼中的單線程線程池的分析是對的。同時我們還可以看出:

一、無論添加多少個任務onPreExecute方法是第一個被執行的,

二、onPostExecute方法的執行和自定義的Runable無關,只和excute()方法有關,也就是隻有調用excute()方法onPostExecute

方法纔會執行,調用execute(new Task("二"))方法這個方法是不會執行的。

上面是對execute()和execute(runnable)方法進行的分析,那麼executeOnExecutor(exec, params)方法呢?他有什麼作用呢?

從executeOnExecutor(exec, params)方法中傳進的參數我們可以出,他是自定義了一個Executor接口對象,也就是自定義了

SerialExecutor類,沒有使用默認的SerialExecutor類。所以如果我們不想要這個單一線程池的效果,那麼我們可以自定義一個

線程池,然後根據我們自己的需要去執行任務,如下代碼:

	@Override
	public void onClick(View view) {
		TestAsyn asyn = new TestAsyn();		
		
		asyn.executeOnExecutor(new TestExecute());		
		asyn.execute();
		TestAsyn.execute(new Task("任務二"));
		TestAsyn.execute(new Task("任務三"));
	}
	
	class TestExecute implements Executor{
		@Override
		public void execute(Runnable r) {
			//這裏還沒有實現,所以上面的任務放進來不會被執行
		}		
	}

上面我們自定義了一個未實現的Executor線程執行體,然後用這個區替換系統默認的已經實現的單一線程池效果的SerialExecutor

在這個類中我們可以根據我們的需要安排任務的執行順序,這就給了我們很大的自由。

以上就是AsyncTask多任務以及其自帶的三個執行方法的解析。至此AsyncTask的分析就已經全部完成了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章