AsyncTask

阅读更多
AsyncTask

                       

                   




AsyncTask





异步的短时间任务,最多到几秒的操作



  • 三个类型

    1.Params 传递给任务的参数

    2.Progress 执行中返回的阶段类型

    3.Result 最终结果的返回类型

  • 4个步骤

    1.onPreExecute 在UI线程中执行一般是用来配置任务

    2.doInBackground 在后台执行,返回类型必须是Result类型,可以调用publishProgress来向UI线程报告进度

    3.onProgressUpdate 在UI线程中执行,可以用来在UI上显示进度条等

    4.onPostExecute 在UI线程中执行,Result被传入作为参数

  • 取消任务

    1.调用cancel可以使接下来调用的isCancel方法返回true

    2.取消任务后在doInBackground 结束后会调用onCancelled 而不是onPostExecute 

    3.cancel只可以设置标志位,并不能立即中断任务,需要在doInBackground 在执行的过程中周期性的去检查isCancel

  • 线程相关

    1.AsyncTask类必须在UI线程中加载(系统自动加载)

    2.AsyncTask实例必须在UI线程中进行构造

    3.不要手动调用doInBackground 等方法

    4.AsyncTask只能执行一次,再次执行会抛出异常

    5.AsyncTask保证所有的回调都是同步的,所以在4个步骤中不必考虑并发问题





    public AsyncTask() {
        //Callable 的包装,将给executor执行
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };
        //控制mWorker执行的future,用来在必要的时候取消执行
        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 occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }


调用execute后实际会转到executeOnExecutor上,代码如下:






/* 这里的exec是可以制定的,默认的是AsyncTask的sDefaultExecutor,这是个SerialExecutor即所有任务需要顺序执行
也可以传入自定义的Executor来实现任务的并发执行
*/

    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;
// 此方法还没有进入到exec中所以onPreExecute还是在UI线程中操作
        onPreExecute();
// 将params传入到mWoeker中,并将包涵mWorker的future送给exec去执行
        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }


默认的执行是在SerialExecutor中执行的,它可以保证所有的AsyncTask的doInBackground是同步执行的





    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
// 这个方法可以保证传进的r都是顺序执行的,即一个结束后另一个才开始
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            //当第一个任务时候会触发,或者当某个任务结束时候下一个task还没有到达的时候也会触发
            //当任务在前一个任务还没有结束就到达了,那么会在上面的scheduleNext直接触发执行
            if (mActive == null) {
                scheduleNext();
            }
        }
//将任务送给THREAD_POOL_EXECUTOR 执行
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }


上面可以看到onPreExecute是在主线程中执行的,然后是doInBackGround在独立的线程中,那么它是又如何回到UI线程中的呢?

这是因为AsyncTask构造了一个基于主线程的Handler ,代码如下:





    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,会调用onProgressUpdate
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }


onProgressUpdate  和 onPostExecute 都是在handler中执行的所以自然是在主线程,而将消息传递给handler的是publishProgress 和 postResult



publishProgress 比较简单就是从Handler 获取小心然后发送,这个在AsyncTask内部没有调用,主要用来给用户自定义的子类在doInBackground中使用



postResult 是在mWorker中定义会在结束后发消息给handler

你可能感兴趣的:(AsyncTask)