AsyncTask使用及源码分析

AsyncTask

AsyncTask使用注意事项:

  • AsyncTask只能被执行(execute方法)一次,多次执行将会引发异常.
  • 任务的取消只能打了一个标记,并不是真正取消,需要手动去掉用;

构建AsyncTask抽象类的三个泛型参数;

  • AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承.继承AsyncTask需要指定如下三个泛型参数:
    • Params:启动任务时输入的参数类型.
    • Progress:后台任务执行中返回进度值的类型.
    • Result:后台任务执行完成后返回结果的类型.

AsyncTask四个方法:

  • onPreExecute();

    执行任务之前,一般做变量的初始化,或者ui的隐藏或者显示;该方法无参数

  • doInBackground(T...params);//对应泛型参数params

    后台执行任务,属于子线程,当调用publishProgress()方法时,会触发系统自动调用onProgressUpdate();

  • onProgressUpdate(T... values);//对应泛型参数progress

    用于更新进度

  • onPostExecute(T...result);//对应泛型参数result

    任务结束后调用,一般处理返回的结果,或者改变ui显示.

AsyncTask历史版本问题:

在Android1.6之前,AsyncTask是串行执行任务,Android1.6时候AsyncTask开始采用线程池处理并行任务,但是从Android3.0开始,为了避免AsyncTask带来的并发错误,又采用线程池串行执行任务,尽管此处,Android3.0后,AsyncTask还是支持并发执行任务,不过需要调用executeOnExecutor()方法.

加载网络图片的实例:

    public class ImageActivity extends Activity {
        private ImageView imageView ;
        private ProgressBar progressBar ;
        private static String URL = "http://pic3.zhongsou.com/image/38063b6d7defc892894.jpg";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.image);
            imageView = (ImageView) findViewById(R.id.image);
            progressBar = (ProgressBar) findViewById(R.id.progressBar);
            //通过调用execute方法开始处理异步任务.相当于线程中的start方法.
            new MyAsyncTask().execute(URL);
        }
    
        class MyAsyncTask extends AsyncTask<String,Void,Bitmap> {
    
            //onPreExecute用于异步处理前的操作
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                //此处将progressBar设置为可见.
                progressBar.setVisibility(View.VISIBLE);
            }
    
            //在doInBackground方法中进行异步任务的处理.
            @Override
            protected Bitmap doInBackground(String... params) {
                //获取传进来的参数
                String url = params[0];
                Bitmap bitmap = null;
                URLConnection connection ;
                InputStream is ;
                try {
                    connection = new URL(url).openConnection();
                    is = connection.getInputStream();
                    //为了更清楚的看到加载图片的等待操作,将线程休眠3秒钟.
                    Thread.sleep(3000);
                    BufferedInputStream bis = new BufferedInputStream(is);
                    //通过decodeStream方法解析输入流
                    bitmap = BitmapFactory.decodeStream(bis);
                    is.close();
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return bitmap;
            }
    
            //onPostExecute用于UI的更新.此方法的参数为doInBackground方法返回的值.
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                //隐藏progressBar
                progressBar.setVisibility(View.GONE);
                //更新imageView
                imageView.setImageBitmap(bitmap);
            }
        }
    }

模拟加载进度条:

    
    public class ProgressActivity extends Activity{
        private ProgressBar progressBar;
        private MyAsyncTask myAsyncTask;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.progress);
            progressBar = (ProgressBar) findViewById(R.id.progress);
            myAsyncTask = new MyAsyncTask();
            //启动异步任务的处理
            myAsyncTask.execute();
        }
    
        //AsyncTask是基于线程池进行实现的,当一个线程没有结束时,后面的线程是不能执行的.
        @Override
        protected void onPause() {
            super.onPause();
            if (myAsyncTask != null && myAsyncTask.getStatus() == Status.RUNNING) {
                //cancel方法只是将对应的AsyncTask标记为cancelt状态,并不是真正的取消线程的执行.
                myAsyncTask.cancel(true);
            }
        }
    
        class MyAsyncTask extends AsyncTask<Void,Integer,Void>{
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                //通过publishProgress方法传过来的值进行进度条的更新.
                progressBar.setProgress(values[0]);
            }
    
            @Override
            protected Void doInBackground(Void... params) {
                //使用for循环来模拟进度条的进度.
                for (int i = 0;i < 100; i ++){
                    //如果task是cancel状态,则终止for循环,以进行下个task的执行.
                    if (isCancelled()){
                        break;
                    }
                    //调用publishProgress方法将自动触发onProgressUpdate方法来进行进度条的更新.
                    publishProgress(i);
                    try {
                        //通过线程休眠模拟耗时操作
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        }
    }

AsyncTask的源码解析:

AsyncTask的使用分两步:


    myAsyncTask = new MyAsyncTask();
            //启动异步任务的处理
    myAsyncTask.execute();

从执行起步任务的起始点开始, 进入execute()方法:


    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING; //状态改变执行中
        onPreExecute(); //执行前准备工作
        mWorker.mParams = params;//赋值
        exec.execute(mFuture); //执行异步任务
        return this;
    }

一个异步进入,先判断该任务是否在执行,或者执行完毕,如果是,则抛出异常,说明一个任务只能被执行一次.否则,将任务状态改变为RUNNING,并将传进来的params传给mWorker, 那么mWorker是什么?,继续看源码:


    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;
    }

可以看到mWorker在构造方法中完成了初始化工作,因为是个抽象类,就new了一个具体子类,实现call方法,并将原子类变量mTaskInvoked=true,最后调用doInbackGround(mParams),并将返回的result作为参数给postResult(),在postResult()方法中:


    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

在postReuslt()中可以看到,采用异步消息机制,发送一个message.what为MESSAGE_POST_RESULT的消息,将异步执行的结果切换到主线,完成线程的切换工作.


    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;
            }
        }
    }

可以看到Handler使用的是Looper.getMainLooper,说明Handler接收消息发生主线程,收到MESSAGE_POST_RESULT执行finish():


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

可以看到在finish()对异步任务是否取消做了判断,如果异步任务已经取消,则调用onCancel()方法,否则调用onPostResult(),这里也可以看到当异步任务被取消后, onPostExecute()是不会执行.最后将状态置为FINISHED.构造函数仅仅只是完成了mWorker的初始化工作,并采用FutureTask将mWorker包装了下,并未真正执行,当然在任务执行结束后,会调用postResultNotInvoked(get()),来查看任务是否已经执行:


    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

如果mTaskInvoked不为true,则postResult(),但是mWorker初始化的时,就已经将mTaskResult置为true,所以这个方法不会调用.

下面看看 exec.execute(mFuture);到底做了什么:


    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

知道exec实际上是sDefaultExecutor:


    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
  
    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);
            }
        }
    }

sDefaultExecutor实际上SerialExecutor的一个实例,其内部维护一个双端队列(数组实现),执行execute(),会调用offer()将任务放入队列尾部, 然后判断mActive否为空,如果为null,则调用scheduleNext()从队列尾部取出一个任务,调用THREAD_POOL_EXECUTOR真正执行任务:


    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    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 THREAD_POOL_EXECUTOR; //可以并行执行的线程池

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

线程池最大支持CUP_COUNT*2+1的线程并发,加上长度为128的阻塞队列,如果任务的数量为CUP_COUNT*2+1+128是否会因为任务数过多而抛出异常,实际上不可能,再来先看下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);
            }
        }
    }


如果此时有10个任务同时调用execute()方法,第个任务加入队列,mActive=null,从队列尾部取出一个任务,然后交给线程池去执行,然后第二任务入队,但是此时mActive不为null,不会执行scheduleNext()方法,只能等待第一个任务执行完毕,再调用scheduleNext().内部虽然是个线程池,但是确实个串行的线程池.

那么AysncTask是否就不能并发执行任务呢? 其实AsyncTask是可以并发执行任务的,不过要调用


    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
        ....
    }

然后自己传入一个可以并发执行任务的线程池,比如AsyncTask提供的THREAD_POOL_EXECUTOR.在AsyncTaskCompat中:

    
    public static <Params, Progress, Result> AsyncTask<Params, Progress, Result> executeParallel(
            AsyncTask<Params, Progress, Result> task,
            Params... params) {
        if (task == null) {
            throw new IllegalArgumentException("task can not be null");
        }

        if (Build.VERSION.SDK_INT >= 11) {
            // From API 11 onwards, we need to manually select the THREAD_POOL_EXECUTOR
            AsyncTaskCompatHoneycomb.executeParallel(task, params);
        } else {
            // Before API 11, all tasks were run in parallel
            task.execute(params);
        }

        return task;
    }

    class AsyncTaskCompatHoneycomb {

        static <Params, Progress, Result> void executeParallel(
                AsyncTask<Params, Progress, Result> task,
                Params... params) {
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
        }

    }

可以看出在API 11之前调用execute()就表示并发执行任务,在API需要调用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)来执行并发任务.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容