一步步完全解析AsyncTask

    做个Android开发的同学们应该都用过AsyncTask,通过继承AsyncTask类实现异步操作,反馈当前异步执行的进度,最后执行的结果反馈给UI主线程。我们在开发中使用AsyncTask,因为它的主要优点使用简单方便、不用关系和主线程交互逻辑和执行过程可控,当然还可以支持取消。说完AsyncTask的优点,下面我们来数数AsyncTask的几宗罪。

    1.不同版本实现对并发支持不一,需要控制线程任务先后的情况难以控制,当我们开发中要求两个任务必须有先后执行顺序,我们Android2.3版本AsyncTask默认是并发执行,无法做到控制执行先后顺序。

    2.不能在主线程以外更新UI;

    3.不能灵活控制线程间任务执行顺序,比如,当我多个任务Task1,Task2,Task3等,我们的Task2和Task3必须等待Task1先运行,而我们的Task2和Task3可以同时运行。这个时候AsyncTask就难以控制。

    4.没完全捕捉AsyncTask运行时候的异常。

    5.AsyncTask难以处理多任务UI交互的问题。

    我们知道了AsyncTask的缺点后,这样我们在以后的开发中就能有的选择什么时候使用AsyncTask,什么时候不使用。

    本着加强对AsyncTask这个类的理解,下面我尝试自己来一步步来实现AsyncTask的功能,努力来解决系统AsyncTask类存在的问题。我们知道AsyncTask的实现本质还是封装对Handler + Thread模式来更新UI的实现,下面我们来实现我们AsyncTask的实现第一版(V1.0):

public abstract class MyAsyncTask<Result> {

	private static final int CORE_POOL_SIZE = 5;
	private static final int MESSAGE_POST_RESULT = 0x1;
	 
	//此处我们新建一个默认CORE_POOL_SIZE大小的线程池
	public static Executor executor = Executors.newFixedThreadPool(CORE_POOL_SIZE); 

	protected final InternalHandler sHandler  = new InternalHandler();

	private Result postResult(Result result) {
		Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new SafeAsyncTaskResult<Result>(this,result));
		message.sendToTarget(); //任务执行完成,给UI线程发消息,我们的消息参数被封装到SafeAsyncTaskResult<Result>类的对象里
		return result;
	}

	public void execute() {
		executor.execute(new FutureTask<Result>(new Callable<Result>() {
			@Override
			public Result call() throws Exception {
				return postResult(doInBackground()); //此处为异步任务执行
			}
		})); 
	}
	
	/*
	 * 实现该方法,真正的异步任务执行的地方
	 */
	protected abstract Result doInBackground();

	private static class InternalHandler<Result> extends Handler {
		 public void handleMessage(Message msg) {
			 SafeAsyncTaskResult<Result> result = (SafeAsyncTaskResult<Result>) msg.obj;
	            switch (msg.what) {
	                case MESSAGE_POST_RESULT:
	                    result.mTask.finish(result.mData); //注意此处我们在hander里处理我们接受的MESSAGE_POST_RESULT(表示任务执行完成)
	                    break;
	            }
	        }
	}
	
	private void finish(Result result){
		 onPostExecute(result);
	}
	
	/*
	 * 任务执行完更新UI	
	 */
	protected abstract void onPostExecute(Result result);

	private static class SafeAsyncTaskResult<Data> {
	        final MyAsyncTask mTask;
	        final Data mData;

	        SafeAsyncTaskResult(MyAsyncTask<?> task, Data data) {
	            mTask = task;
	            mData = data;
	        }
	    }
}

我们看我们的V1.0实现,基本实现一个Handler + Thread模式的异步线程操作。但是还存在很多不少问题,首先还没有实现基本的取消功能,然后,我们也做不到线程执行顺序,还做不到在子线程更新UI,还有不能捕捉所有线程异常,最后,做不到灵活实现控制线程执行顺序。下面我们V1.1版本重点来支持线程的取消和解决在子线程更新我们的UI。我们知道FutureTask接口支持取消操作,因此我们把FutureTask作为类MyAsyncTask的成员变量。下面我们来看V1.2版本的实现如下:

public abstract class MyAsyncTask<Result> {

	private static final int CORE_POOL_SIZE = 5;
	private static final int MESSAGE_POST_RESULT = 0x1;
	 
	//此处我们新建一个默认CORE_POOL_SIZE大小的线程池
	public static Executor executor = Executors.newFixedThreadPool(CORE_POOL_SIZE); 

	//保证多个线程对MyAsyncTask取消操作,其他线程立刻可见性
	private final AtomicBoolean mCancelled = new AtomicBoolean(); 
	
	protected final InternalHandler sHandler;
	
	private FutureTask<Result> futureTask;
	
	public MyAsyncTask(){
		if (Looper.myLooper() != Looper.getMainLooper()) {
			 // 当MyAsyncTask不在主线程实例化,给Handler指定Looper,可以实现在子线程更新主线程
			sHandler = new InternalHandler(Looper.getMainLooper()); 
		} else {
			sHandler = new InternalHandler();
		}

		futureTask = new FutureTask<Result>(new Callable<Result>() {
			@Override
			public Result call() throws Exception {
				return postResult(doInBackground()); //此处为异步任务执行
			}
		});
	}

	private Result postResult(Result result) {
		Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new SafeAsyncTaskResult<Result>(this,result));
		message.sendToTarget(); //任务执行完成,给UI线程发消息,我们的消息参数被封装到SafeAsyncTaskResult<Result>类的对象里
		return result;
	}

	public void execute() {
		onPreExecute();
		executor.execute(futureTask); 
	}
	
	/*
	 * 当异步任务开始前的操作
	 */
	private void onPreExecute() {
		
	}

	public  boolean cancel(boolean mayInterruptIfRunning) {
		mCancelled.set(true);
        return futureTask.cancel(mayInterruptIfRunning);
    }
	
	/*
	 * 判断当前任务是否取消
	 */
	public boolean isCanceled(){
		return mCancelled.get();
	}
	
	/*
	 * 实现该方法,真正的异步任务执行的地方
	 */
	protected abstract Result doInBackground();

	private static class InternalHandler<Result> extends Handler {
		
		public InternalHandler() {
			super();
		}
		
		public InternalHandler(Looper looper) {
			super(looper);
		}
		
		
		 public void handleMessage(Message msg) {
			 SafeAsyncTaskResult<Result> result = (SafeAsyncTaskResult<Result>) msg.obj;
	            switch (msg.what) {
	                case MESSAGE_POST_RESULT:
	                    result.mTask.finish(result.mData); //注意此处我们在hander里处理我们接受的MESSAGE_POST_RESULT(表示任务执行完成)
	                    break;
	            }
	        }
	}
	
	private void finish(Result result){
		 onPostExecute(result);
	}
	
	/*
	 * 任务执行完更新UI	
	 */
	protected abstract void onPostExecute(Result result);

	private static class SafeAsyncTaskResult<Data> {
	        final MyAsyncTask mTask;
	        final Data mData;

	        SafeAsyncTaskResult(MyAsyncTask<?> task, Data data) {
	            mTask = task;
	            mData = data;
	        }
	    }
}

然后我们V1.3版本重点在控制线程并发和线程协作处理上,在V1.2版本我们的线程处理直接建立了一个大小固定的线程池来处理问题,在默认的4.0及以上,AsyncTask默认线程池线性执行系列线程,并且可以并行执行系列线程。此处我们直接参看源码4.0对AsyncTask的执行控制,我们在源码里看到我们系统默认初始化一个并发的线程池THREAD_POOL_EXECUTE线程池,同时初始化了一个类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();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

我们注意到scheduleNext方法的实现实际上还是调用THREAD_POOL_EXECUTOR并发的线程池来执行线程,这样我们知道AsyncTask控制线程池顺序执行任务时间上通过控制并发线程池顺序执行来达到目的。通过这里控制并发的线程池线性执行线程,我们可以大胆的说,如果我们设计合理的话,我们这里也可以通过封装实现更灵活的控制线程池实现。鉴于水平有限,没能写出更灵活的控制线程执行顺序的执行器。下面我们给出V1.3版本的代码实现功能,已经很接近系统4.0的AsyncTask的源码实现。

public abstract class MyAsyncTask<Result> {

	private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
	private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
	private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
	private static final int MESSAGE_POST_RESULT = 0x1;
	private static final int KEEP_ALIVE = 1;
	
	private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128); 
	
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 
    
    public static final Executor THREAD_POOL_EXECUTOR
    	= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
            TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    
    //Android源码AsyncTask 实现sDefaultExecutor用关键字volatile,是因为 setDefaultExecutor方法可以修改AsyncTask默认实现
    private static Executor sDefaultExecutor = SERIAL_EXECUTOR; 
    
    //任务完成或者取消的回调接口
    private  AysncTaskFinishedListener finishListener;
    
    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();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    
	//保证多个线程对MyAsyncTask取消操作,其他线程立刻可见性
	private final AtomicBoolean mCancelled = new AtomicBoolean(); 
	
	protected final InternalHandler sHandler;
	
	private FutureTask<Result> futureTask;
	
	public MyAsyncTask(){
		if (Looper.myLooper() != Looper.getMainLooper()) {
			 // 当MyAsyncTask不在主线程实例化,给Handler指定Looper,可以实现在子线程更新主线程
			sHandler = new InternalHandler(Looper.getMainLooper()); 
		} else {
			sHandler = new InternalHandler();
		}

		futureTask = new FutureTask<Result>(new Callable<Result>() {
			@Override
			public Result call() throws Exception {
				return postResult(doInBackground()); //此处为异步任务执行
			}
		});
	}
	
	protected void setFinishedListener(AysncTaskFinishedListener finishListener) {
		this.finishListener = finishListener;
	}

	private Result postResult(Result result) {
		Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new SafeAsyncTaskResult<Result>(this,result));
		message.sendToTarget(); //任务执行完成,给UI线程发消息,我们的消息参数被封装到SafeAsyncTaskResult<Result>类的对象里
		return result;
	}

	/*
	 * 默认线程线性执行
	 */
	public void execute() {
		onPreExecute();
		sDefaultExecutor.execute(futureTask); 
	}
	
	/*
	 * 显式调用并行执行
	 */
	public void executeOnExecutor(){
		onPreExecute();
		THREAD_POOL_EXECUTOR.execute(futureTask);
	}
	
	/*
	 * 当异步任务开始前的操作
	 */
	private void onPreExecute() {
		
	}

	public  boolean cancel(boolean mayInterruptIfRunning) {
		mCancelled.set(true);
        return futureTask.cancel(mayInterruptIfRunning);
    }
	
	/*
	 * 判断当前任务是否取消
	 */
	public boolean isCanceled(){
		return mCancelled.get();
	}
	
	/*
	 * 实现该方法,真正的异步任务执行的地方
	 */
	protected abstract Result doInBackground();

	private static class InternalHandler<Result> extends Handler {
		
		public InternalHandler() {
			super();
		}
		
		public InternalHandler(Looper looper) {
			super(looper);
		}
		
		
		 public void handleMessage(Message msg) {
			 SafeAsyncTaskResult<Result> result = (SafeAsyncTaskResult<Result>) msg.obj;
	            switch (msg.what) {
	                case MESSAGE_POST_RESULT:
	                    result.mTask.finish(result.mData); //注意此处我们在hander里处理我们接受的MESSAGE_POST_RESULT(表示任务执行完成)
	                    break;
	            }
	        }
	}
	
	private void finish(Result result){
		 if(isCanceled()){
			 if(finishListener != null)
				 finishListener.onCancelled();
		 }else{
			 onPostExecute(result);
			 if(finishListener != null)
				 finishListener.onPostExecute();
		 }
		 
	}
	
	/*
	 * 任务执行完更新UI	
	 */
	protected abstract void onPostExecute(Result result);

	private static class SafeAsyncTaskResult<Data> {
	        final MyAsyncTask mTask;
	        final Data mData;

	        SafeAsyncTaskResult(MyAsyncTask<?> task, Data data) {
	            mTask = task;
	            mData = data;
	        }
	    }
	
	public static interface AysncTaskFinishedListener {
		void onCancelled();

		void onPostExecute();
	}
}

V1.3的代码没有能达到线程池对代码的更灵活的控制过程,我们可以通过封装MyAsyncTask的操作来实现。以下的实现参考了github上的android-lite-async项目的实现,对MyAsyncTask的实现如下:

public class TaskExecutor {
    /**
     * 关卡异步任务执行器
     *
     * @return
     */
    public static CyclicBarrierExecutor newCyclicBarrierExecutor() {
        return new CyclicBarrierExecutor();
    }
    
	public static class CyclicBarrierExecutor {
        ArrayList<MyAsyncTask<?>> taskList = new ArrayList<MyAsyncTask<?>>();

        public CyclicBarrierExecutor put(MyAsyncTask<?> task) {
            if (task != null) taskList.add(task);
            return this;
        }

        public void start(final MyAsyncTask< ?> finishTask) {
            start(finishTask, 0, null);
        }

        public void start(final MyAsyncTask<?> endOnUiTask, final long time, final TimeUnit unit) {
            final CountDownLatch latch = new CountDownLatch(taskList.size());
            new MyAsyncTask<Boolean>() {

                @Override
                protected Boolean doInBackground() {
                    try {
                        if (unit == null) 
                        	latch.await();
                        else 
                        	latch.await(time, unit);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return true;
                }

                @Override
                protected void onPostExecute(Boolean aBoolean) {
                    endOnUiTask.execute();
                }
            }.execute();
            startInternal(latch);
        }

        private void startInternal(final CountDownLatch latch) {
            for (MyAsyncTask<?> each : taskList) {
                each.setFinishedListener(new MyAsyncTask.AysncTaskFinishedListener() {

                    @Override
                    public void onPostExecute() {
                        latch.countDown();
                    }

                    @Override
                    public void onCancelled() {
                        latch.countDown();
                    }
                });
                each.execute();
            }
        }
    }
}
以上代码我们通过CountDownLatch来控制线程的先后执行顺序,已经能达到我们比较灵活的控制代码的执行顺序。通过以上的代码分析,关于AsyncTask的实现,都是围绕对handler + Thread模式展开,无非封装的强大与否。如果想继续深入学习对handler + Thread的封装,大家可以学习学习github的Android客户端封装的SafeAsyncTask实现。ps:github的 android客户端值得学习的地方可远非只有SafeAsyncTask的代码封装,很值得感兴趣的同学可以对整个代码框架深入学习。

通过上面的分析,我们也知道AsyncTask就算优化解决了以上的几宗罪(第5条除外),我们的AsyncTask也不是万能的。在我们的开发中还是很多线程交互的情况无法用AyncTask解决,比如,第五条的问题,还有比如,当我们两个线程相互等待的情况,如,任务一请求接口数据返回任务2来处理,任务一等待回调任务二数据,然后继续执行任务一(ps:在我们的开发,这种情况的出现很大一部分原因是接口接口来不及处理或者处理的不及时,最后,只能我们交给我们客户端来解决)。

转载请注明出处:http://blog.csdn.net/johnnyz1234/article/details/47092227







评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值