深入理解AsyncTask实现原理

摘要:在 android 中实现耗时的操作有很多种实现方式,比如线程(线程池、Callable、FutureTask等等),这些实现方式有各自的好处,具体使用也有差别,一般线程执行为是没有结果返回的,利用FuTureTask可以实现返回结果。

    在 Android 中用异步任务来实现耗时操作可以说是很方便,开发者不需要过多关注怎么在 UI 线程和子线程之间的操作。

    在分析 AsyncTask 之前先看一下官方 Demo 如何使用这个类

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

 *     protected Long doInBackground(URL... urls) {

 *         int count = urls.length;

 *         long totalSize = 0;

 *         for (int i = 0; i < count; i++) {

 *             totalSize += Downloader.downloadFile(urls[i]);

 *             publishProgress((int) ((i / (float) count) * 100));

 *             // Escape early if cancel() is called

 *             if (isCancelled()) break;

 *         }

 *         return totalSize;

 *     }

 *

 *     protected void onProgressUpdate(Integer... progress) {

 *         setProgressPercent(progress[0]);

 *     }

 *

 *     protected void onPostExecute(Long result) {

 *         showDialog("Downloaded " + result + " bytes");

 *     }

 * }

这里主要是三个方法:onPreExecute,doInBackground,onPostExecute

这里做个简单说明一下 onPreExecute 用于实现子线程开始之前的准备工作,例如初始化进度的Bar,doInBackground 这个方法用于进行耗时操作,比如从网络下载东西,数据库操作等等,onPostExecute 用于异步操作之后的结果显示。

     知道了使用之后这里提出两个疑问:1、怎么在子线程跟 UI 线程之间切换。

           2、doInBackground 执行完的结果怎么作为参数给 onPostExecute。

知道了这两个答案之后那么我们对这个类也就了解的七七八八了。

首先来看  AsyncTask 的构造函数

public AsyncTask(@Nullable Looper callbackLooper) {

        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()

            ? getMainHandler(): new Handler(callbackLooper);

           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;

            }

        };

AsyncTask 有多个构造函数,最后都是调用这个函数,这里有两个类需要注意的是 mHandler  、mWorker , 这个 mHandler 很好理解就是就是主线程的 Handler,估计切换到 UI 线程就是靠这个的了。那这个 mWorker 呢? 是用来干什么的呢? 别急这里先看这个类是怎么实现的:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {

        Params[] mParams;

    }

很简单就是实现一个 Callable 接口,这里有个 call 方法,该方法是在子线程中执行的,这里有两句比较眼熟的语句:

result = doInBackground(mParams);

 postResult(result);

doInBackground 这个没什么好说就是刚方法执行完后返回一个结果, call 方法是在子线程,该方法肯定也是在子线程。

看看 postResult 方法是如何实现的

private Result postResult(Result result) {

        @SuppressWarnings("unchecked")

        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,

                new AsyncTaskResult<Result>(this, result));

        message.sendToTarget();

        return result;

    }

getHandler()就是初始化的 mHandler ,该类实现如下

 private static class InternalHandler extends Handler {

        public InternalHandler(Looper looper) {

            super(looper);

        }

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

            }

        }

    }

到这里就回答了一开始的两个问题了。

AsyncTask 还有个很重要的方式就是 execute,

public final AsyncTask<Params, Progress, Result> execute(Params... params) {

        return executeOnExecutor(sDefaultExecutor, params);

    }

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,

            Params... params) {

        if (mStatus != Status.PENDING) {//一个 AsyncTask 实例,该方法只可以执行一次

            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();//UI线程

        mWorker.mParams = params;

        exec.execute(mFuture); //线程池来执行

        return this;

    }

到这里 AsyncTask 基本上是分析完成了,关于里面线程池的话还有更多的细节,可以自定义线程池或者用默认的线程池,线程池又有对线程的数量做了限制

猜你喜欢

转载自blog.csdn.net/johndon_forever/article/details/106444315