欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AsyncTask的使用以及源码分析

程序员文章站 2024-03-24 15:43:34
...

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