cancel ngs trac 下载 深入理解 回收 生命 str
众所周知,在 Android 中如果要执行耗时的操作,一般是在子线程中处理,使用 new Thread 的方法实现是最常见的方法之一。今天,我们要讲的是另外一个,Android 提供的异步任务类 AsyncTask,底层是使用线程池实现的。
一、Android 的线程
线程是操作系统的最小执行单位,它的创建和销毁都会消耗一定的系统资源,如果频繁的创建和销毁,显然不是高效的做法,正确的做法是,采用线程池,缓存一定量的线程,通过复用这些线程,避免造成极大的系统开销。
二、AsyncTask
这是一个抽象类,使用方便,代码简洁,所以说是一个轻量级的异步类。它可以在线程池中执行后台任务,然后把执行的进度和结果通过 Handler 传给 UI 线程进而刷新视图。
该类的声明如下:
- public abstract class AsyncTask < Params,
- Progress,
- Result >
其中各个参数的含义如下:
Params:开始异步任务执行时传入的参数类型;
Progress:异步任务执行过程中,返回下载进度值的类型;
Result:异步任务执行完成后,返回的结果类型;
如果 AsyncTask 确定不需要传递具体参数,那么这三个泛型参数可以用 Void 来代替。
三、AsyncTask 源码
AsyncTask 内部封装了 2 个线程池:SerialExecutor 和 THREAD_POOL_EXECUTOR,和 1 个 Handler(IntentHandler)。其中 SerialExecutor 线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR 线程池才真正地执行任务,InternalHandler 用于从工作线程切换到主线程。部分源码如下:
- 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);
- }
- }
- }
- ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
- CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
- sPoolWorkQueue, sThreadFactory);
- threadPoolExecutor.allowCoreThreadTimeOut(true);
- THREAD_POOL_EXECUTOR = threadPoolExecutor;
- private static class InternalHandler extends Handler {
- public InternalHandler() {
- super(Looper.getMainLooper());
- }
- @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
- @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;
- }
- }
- }
四、注意事项
1、因为执行后的结果要传递到主线程,所以使用 Handler 进行工作线程和主线程的切换,所以 AsyncTask 创建实例和 execute 需要在主线程调用;
2、onPreExecute(),onProgressUpdate(Progress... values),onPostExecute(Result result),onCancelled() 方法是在主线程执行的,而 doInBackground(Params... params) 是在工作线程执行;
3、执行顺序:onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute(),如果不需要执行更新进度则为 onPreExecute() --> doInBackground() --> onPostExecute(),其中 publishProgress 方法在 doInBackground 方法中调用,会触发 onProgressUpdate 方法;
4、AsyncTask 还提供了 onCancelled() 方法,它同样在主线程中执行,当异步任务取消时,onCancelled() 会被调用,这个时候 onPostExecute() 则不会被调用,但是要注意的是,AsyncTask 中的 cancel() 方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在 doInBackground() 判断终止任务。就好比想要终止一个线程,调用 interrupt() 方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。
5、一个任务实例只能执行一次,如果执行第二次将会抛出异常。
五、AsyncTask 使用不当的后果
1、生命周期:AsyncTask 不与任何组件绑定生命周期,所以在 Activity 或者 Fragment 中创建执行 AsyncTask 时,最好在 Activity 或 Fragment 的 onDestory() 调用 cancel(boolean);
2、内存泄漏:如果 AsyncTask 被声明为 Activity 的非静态的内部类,那么 AsyncTask 会保留一个对创建了 AsyncTask 的 Activity 的引用。如果 Activity 已经被销毁,AsyncTask 的后台线程还在执行,它将继续在内存里保留这个引用,导致 Activity 无法被回收,引起内存泄露;
3、 结果丢失:屏幕旋转或 Activity 在后台被系统杀掉等情况会导致 Activity 的重新创建,之前运行的 AsyncTask(非静态的内部类)会持有一个之前 Activity 的引用,这个引用已经无效,这时调用 onPostExecute() 再去更新界面将不再生效。
参考链接:
http://www.jianshu.com/p/817a34a5f200
深入理解 AsyncTask
来源: http://www.bubuko.com/infodetail-2084294.html