AsyncTask多任务执行

本文深入探讨了Android中的AsyncTask如何实现多任务执行,详细分析了SerialExecutor的工作原理,指出即使任务不在doInBackground中执行,也能通过execute(runnable)放入线程池。通过实例展示了execute()、execute(runnable)和executeOnExecutor(exec, params)的区别,强调了onPreExecute的执行顺序及onPostExecute与自定义Runnable无关。最后讨论了如何自定义Executor以满足特定的并发需求。" 133170116,20038292,使用.NET进行HTTP请求调用,"['.NET', 'HTTP', '网络编程', 'API集成']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过上篇博客对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的分析就已经全部完成了。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值