美文网首页
AsyncTask的使用及其原理

AsyncTask的使用及其原理

作者: pisfans | 来源:发表于2019-08-12 11:27 被阅读0次

    概述

    Android 已封装好的轻量级异步类。内置一个线程池用于异步任务,另一个线程池用于排队(实际不是线程池)。一个默认绑定mainLooper的Handler用于UI线程。

    使用

    • public abstract class AsyncTask<Params, Progress, Result> Params 传参的类型,Progress 进度的类型,Result 返回结果的类型
    • execute(Params... params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。UI线程调用。
    • onPreExecute():在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些准备工作。
    • doInBackground(Params... params) 关键方法,用于执行较为费时的操作,在onPreExecute()完成后立即执行,此方法将接收输入参数和返回计算结果。doInBackground方法接收的参数就是execute()中传入的参数:另外在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
    • onProgressUpdate(Progress... values),如果调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。否则不执行
    • onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果(就是doInBackground方法返回的结果)将做为参数传递到此方法中,直接将结果显示到UI组件上。
    • cancel(boolean)方法,可以取消任务。这个方法会产生的影响是:之后调用的iscancelled()会返回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;
        }
    

    THREAD_POOL_EXECUTOR 是真正用于异步任务的线程池。可以看到它是静态的,也就是每次new AsyncTask()都是用的同一个线程池。

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//ArrayDeque依赖于可变数组来实现的双端队列,可根据需求自动进行扩容。
            Runnable mActive;//当前执行的任务
    
            public synchronized void execute(final Runnable r) {
                mTasks.offer(new Runnable() {//offer向队列中插入一个元素,并返回true,如果队列已满,返回false(add在满时报错)
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                if ((mActive = mTasks.poll()) != null) {//poll取出队列头部的元素,并从队列中移除
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }
    

    SERIAL_EXECUTOR 是实现了Executor 接口,但内部操作是把Runnable 任务放入一个ArrayDeque(双端队列)。并且每执行完一个取出下一个任务执行。其实它不是线程池。
    AsyncTask.execute()默认会调用到这个对象执行,它会一个个的取出任务再用真正的线程池THREAD_POOL_EXECUTOR执行,由此可见,用一个AsyncTask对象执行多个任务会是串行执行的。那么如何让它并行执行呢?改为调用AsyncTask.executeOnExecuter(AsyncTask.THREAD_POOL_EXECUTOR,"")就可以了。

     public AsyncTask(@Nullable Looper callbackLooper) {// 默认构造方法会走到这里
            mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                ? getMainHandler()// 一般是绑定mainLooper的内置的Handler类
                : new Handler(callbackLooper);// 特殊情况
    
            mWorker = new WorkerRunnable<Params, Result>() { // 继承callable的类
                public Result call() throws Exception {
                    mTaskInvoked.set(true);// 调用标识,FutureTask的done方法里调postResultIfNotInvoked会判断
                    Result result = null;
                    try {
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);// 设置线程的优先级
                        //noinspection unchecked
                        result = doInBackground(mParams);//这里调关键方法doInBackground,执行耗时任务,并获取结果
                        Binder.flushPendingCommands(); //将进程中未执行的命令,一并送往CPU处理
                    } catch (Throwable tr) {
                        mCancelled.set(true);//如果运行异常,设置取消的标志
                        throw tr;
                    } finally {
                        postResult(result);//发送结果
                    }
                    return result;
                }
            };
            //一个包装任务的包装类,与callable结合使用
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {//在执行完任务做一道检查,将没被调用的Result也一并发出.这个方法根据上面的mTaskInvoked判断
                        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);//如果发生异常,则将结果滞null发出.
                    }
                }
            };
        }
    

    callable与runnable的区别是,他的call方法有返回值。所以AsyncTask没有用runnable而是用的

    相关文章

      网友评论

          本文标题:AsyncTask的使用及其原理

          本文链接:https://www.haomeiwen.com/subject/iyeadctx.html