AsyncTask多任务执行

通过上篇博客对AsyncTask源码进行分析之后,我们对AsyncTask的任务执行有了一个大致了解,但是在那篇博客中我有一个

问题还没有分析到,那就是线程执行体SerialExecutor类,下面我们来看一下SerialExecutor类的源码。

    private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        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{	
		@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);
		}
	}
}


执行结果:

AsyncTask多任务执行_第1张图片


AsyncTask多任务执行_第2张图片

从执行结果中我们可以看出,每次运行的结果是不同的,但是有一点是确定的,那就是任务添加的顺序就是结果的输出顺序,这也印证了

之前对源码中的单线程线程池的分析是对的。同时我们还可以看出:

一、无论添加多少个任务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的分析就已经全部完成了。


你可能感兴趣的:(android,开发)