AsyncTask的使用以及源码分析

AsyncTask详解

引言: 在Android的实际开发中,经常会涉及到线程的通讯,例如我们获取一张图片,先从网络获取成功之后再页面中,像网络操作是需要在后台线程中进行的,但是展示的时候需要将数据发送到主线程中,这期间就涉及到线程的通讯,当然线程的通讯有很多种,例如谷歌推出的Handler,当然常见的进程通讯中的Binde机制也是可以的,谷歌为了更好的实现线程通讯也提供了一个比较好用的类,这就是AsyncTask.
这篇文章不只是讲述AsyncTask的使用,为了更好的理解AsyncTask机制,也会对源码进行一定的分析.
在此之前需要了解以下内容

Handler :
谷歌为解决不同线程之间的通讯问题而推出的一个类,开发中经常用到
ThreadFactory :
线程工厂,用于统一创建指定线程
AtomicInteger :
用于获取自增Integer的类,可以指定初始化的种子
AtomicBoolean :
用于获取自增Booleanr的类,可以指定初始化的种子
Executor :
线程池的统一实现接口,在该类中自定义实现了一个线程池SerialExecutor
Callable :
有返回值的线程,常用的创建方式有直接创建Thread和通过Runnable的方式创建Thread,但是这两种方式没有返回值
FutureTask :
该类用于包裹callable或者runnable,用于异步的获取执行结果,可以通过get()方法获取返回值
ArrayDeque :
通过数组实现的循环队列,传统的队列是先进先出,该队列可以通过两端获取数据,这篇文章写的挺好的,可以看一下
https://www.cnblogs.com/wxd0108/p/7366234.html

使用方法

使用方法的话不是很复杂,常用重写的方法有doInBackground(),onProgressUpdate(),onPostExecute(),onCancelled()分别表示后台数据的处理,进度的更新,完成的结果以及取消

    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");
        }
        //当取消之后调用的方法
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }
        //使用方法
        DownloadFilesTask task = new DownloadFilesTask();
        //消息的发送
        task.execute();
        //消息的取消
        task.cancel(true);

开头静态代码块

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

在静态代码快中主要是创建了一个线程池,线程池的最大线程大小根据cpu的核心数计算,最大值为4,最小值为2

SerialExecutor

内部类,最终执行execute()的时候,会调用该类的execute()方法

    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
           //插入runnable到队列的尾部
            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);
            }
        }
    }

构造方法

构造方法一共有三个,但是有两个方法是隐藏,但最终调用的是第三个

    public AsyncTask(@Nullable Looper callbackLooper) {
        //获取一个Handler,该Handler主要是主线程Hnadler,因为有两个构造方法是隐藏的QAQ
        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
                    //回调doInBackground方法,该方法是用户需要手动去实现的方法,获取具体的结果值
                    result = doInBackground(mParams);
                    //线程更新
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    //将当前状态置为取消状态
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    //将获取的结果通过Handler发送出去
                    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);
                }
            }
        };
    }

我们可以看到在构造方法主要是创建了两个对象,分别是WorkerRunnableFutureTask,这两个方法
主要是线程的管理,根据线程获取的值进行相应的的操作,取消,发送进度或者是完成发送结果

postResult(),postResultIfNotInvoked()

消息的发送,会在InternalHandler中处理相关的消息

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

postResult(),postResultIfNotInvoked()

消息进度的发送,会在InternalHandler中处理相关的消息,有用户主动调用,回调结果在onProgressUpdate中,用户可以根据不同进度进行相关的显示

    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            //发送进度消息
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

executeOnExecutor()

当用户调用execute()方法的时候会走该方法,通常情况下只能走一次,因为里面有判断,但是如果调用的是execute(Runnable runnable)则不会限制

    @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();
        //执行任务,默认的是```SerialExecutor```中的方法,前面介绍过
        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

总结

AsyncTask是谷歌为了方便不同线程的通讯而做的一个类,适合简单的线程通讯,可以很方便的在UI线程和子线程之间进行消息的传递而无需创建Handler或者是多余的线程,但是不适合做耗时的操作如果需要耗时操作可以用Executor,ThreadPoolExecutor或者FutureTask

猜你喜欢

转载自blog.csdn.net/Buuuuuuuuu/article/details/80067042