AsyncTask 使用小结

相信各位对 AsyncTask 不会陌生,虽然它有如下弊端:

1. 如果在activiy内部new 一个AsyncTask, 横竖屏切换生成一个新的activity,等结果返回时,处理不好容易出现NPE。

2. 容易出现内存泄漏,如果AsyncTask 进行比较耗时的IO操作(网络操作, 打开一个文件等等),在activity onDestroy的时候没有cancel的话,容易

造成该Activity不能被GC回收(AsyncTask 在Activity内部执行耗时操作)。

3. 如果调用 executeOnExecutor, 如果等待queue里面的请求过多没有得到及时处理,容易造成RejectException, 具体原因我在我的博客已经有所介绍(AsyncTask RejectedExecutionException 小结)。

闲话少说, 本文的重点不在于介绍AsyncTask的优缺点,而是一直有一个问题困扰我,为什么AsyncTask 里面既能进行UI 操作,又能进行耗时的操作。

让我们从代码角度来分析这个问题, 首先看他的构造函数:

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }
public class FutureTask<V> implements RunnableFuture<V>
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

从上面的代码可以看出, mWorker 实际上就是一个  Callable, 而 mFuture 就是一个Thread, 构造函数中将Callable 作为参数传给了 FutureTask,下面

我们看看FutureTask 中的相关实现:

public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

可以看到 result = c.call(); 在run方法中被调用, 实际就是 result = doInBackground(mParams); 被调用,因为该方法是在子线程里面执行,所以可以执行耗时操作。 继续读代码,在doInBackground 执行后,在finally中 postResult(result);继续被执行,

 private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }
 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.wh所以at) {
                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;
            }
        }
    }

相信上面的代码大家都能看懂,值得说明的是,因为 InternalHandler的构造函数使用 mainlooper,所以 handleMessage 当然可以进行UI 操作。

继续看源码:

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

总结一下,虚函数 doInBackground 在Thread(FutureTask)run方法执行,所以能进行耗时操作,而InternalHanlder 通过获得mainlooper,在 handleMessage中调用 onPostExecute 从而保证了UI 操作可以在onPostExecute执行。这个过程实际就是模板模式。

时间: 2024-08-12 10:54:00

AsyncTask 使用小结的相关文章

AsyncTask RejectedExecutionException 小结

在使用Asynctask时,相信有些朋友会遇到以下RejectedExecutionException: Java.util.concurrent.RejectedExecutionException: Task [email protected] rejected from [email protected][Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 0] at andro

AsyncTask原理

1.对于耗时的操作(如上传下载.读写数据库等),为了不阻塞主线程,我们的一般方法是开启“子线程”.如果需要更新UI,则需要使用handler 2.如果耗时的操作太多,那么我们需要开启太多的子线程,这就会给系统带来巨大的负担,随之也会带来性能方面的问题.在这种情况下我们就可以考虑使用类AsyncTask来异步执行任务,不需要子线程和handler,就可以完成异步操作和刷新UI. 3.AsyncTask的构造方法有三个模板参数 Params(传递给后台任务的参数类型) Progress(后台计算执行

AsyncTask和Handler的优缺点比较(更新线程的问题总结

AsyncTask和Handler的优缺点比较: http://blog.csdn.net/onlyonecoder/article/details/8484200 Handler主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 当应用程序启动时,Android首先会开启一个主线程, 主线程为管理界面中的UI控件,进行事件分发,更新UI只能在主线程中更新,子线程中操作是危险的.这个时候,Handler就需要出来解决这个复杂的问题.由于Handler运行在主线程中(UI线程中),它与子线

Android开发实践:多线程编程小结

我们知道,Android系统为了提高程序的实时响应能力,不允许在UI线程中进行耗时的操作,否则会出现ANR异常,因此必须将耗时的任务放到非UI线程中执行.Android/Java提供了很多类来帮助大家完成异步操作,比如:Thread类,Timer类,AsyncTask类,HandlerThread类,以及Executor接口.这些类都分别在什么场合下使用呢? 本文简单地总结一下Android开发中常见的多线程类型和解决方案,并比较和分析了各个方案的区别,以便更好地理解和应用这些API接口. 1.

Android 结合实例学会AsyncTask的用法

AsyncTask执行时经过四个步骤,执行四个方法: 1.onPreExecute(),运行在UI线程,可以设置或修改UI控件,如显示一个进度条 2.doInBackground,运行在后台线程,不可以设置或修改UI控件,该方法的执行时机是:onPreExecute()执行完毕立即调用该方法,在方法中进行耗时操作,可以在该方法中调用publishProgress方法来发布当执行的进度,调用publishProgress方法后就会立即触发onProgressUpdate方法 3.onProgres

Android AsyncTask 封装初步一

AsyncTask基本使用 先从最熟悉的Task使用开始说起,给出LastDaysTask作为实例如下 @SuppressLint("NewApi") private class LastDaysTask extends AsyncTask<Void, Integer, Boolean>{ @Override protected void onPreExecute() { //TODO UI线程或者主线程 } @Override protected Boolean doIn

Android:AsyncTask源码解析

简单实例 这里直接拿以前写过的一个小Demo,根据这个Demo来分析源码. public class MainActivity extends ActionBarActivity { ... Private MyAsyncTask asyncTask; protected void onCreate(Bundle savedInstanceState) { ... asyncTask = new MyAsyncTask(); // 点击button进行异步任务 button.setOnClick

Android 结合实例学会AsyncTask的使用方法

AsyncTask运行时经过四个步骤,运行四个方法: 1.onPreExecute(),执行在UI线程,能够设置或改动UI控件,如显示一个进度条 2.doInBackground,执行在后台线程,不能够设置或改动UI控件,该方法的执行时机是: onPreExecute()运行完成马上调用该方法,在方法中进行耗时操作,能够在该方法中调用publishProgress方法 来公布当运行的进度,调用publishProgress方法后就会马上触发onProgressUpdate方法 3.onProgr

Android异步任务AsyncTask的使用与原理分析

在上一篇文章<Android缓存机制&一个缓存框架推荐>中说到,在了解了Android缓存机制后我准备自己动手写一个LruCache和DiskLruCache二级缓存的轻量级的图片请求框架,在思考如何搭建这个框架时,纠结于用何种方式去下载图片,是直接new出一个线程呢,还是用看起来稍微高大上档次一点的AsyncTask异步任务来处理?思来想去,还是虚荣心作怪,还是用AsyncTask吧,正好这个工具类我之前用的也比较少,对它的原理也不是很清楚,趁这个机会,好好学一下AsyncTask的