安卓开发学习之异步任务源码阅读

背景

异步任务AsyncTask是Android里自带的异步处理任务(网络请求等)的工具类,使用起来很方便,如今记录一下我对它的源码的阅读过程。

源码取自Android8.0

使用

常见的使用方式之一如下:

        AsyncTask<String, Void, String> asyncTask = new AsyncTask<String ,Void, String>() {

            @Override
            protected void onPreExecute() {

            }

            @Override
            protected String doInBackground(String... strings) {
                return null;
            }

            @Override
            protected void onProgressUpdate(Void... values) {
            }

            @Override
            protected void onPostExecute(String s) {

            }
        };
        asyncTask.execute();

构造方法里的三个泛型参数的类型,分别是参数的类型(String),进度条的类型(Void就是没有进度条)和结果类型(String)

其他的使用方式不管是继承异步任务,还是匿名类的方式,都换汤不换药。其中那四个方法,除了doInBackground()是在子线程里执行的,也是我们必须实现的方法,其他三者都是在主线程里执行的,不必我们实现的(但用来处理结果的onPostExecute()最好还是实现)

最后的execute()不能漏掉,否则任务不会执行的。

下面我从构造方法开始,记录对其源码的阅读

源码阅读

AsyncTask构造方法

构造方法的代码如下

    public AsyncTask() {
        this((Looper) null);
    }

    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper); // 传进来的callbackLooper是null,所以mHandler一定是主线程的handler

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    // 线程的优先级:后台线程
                    result = doInBackground(mParams);
                    // doInBackground()在这里执行,显然是在子线程
                    Binder.flushPendingCommands();
                    // 清空Binder命令
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result); // 给mHandler发送结果,所以结果肯定是在主线程里处理的
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                // 如果因为某种原因未执行任务,还是尝试把结果返回(只是这里返回的是null)
                try {
                    postResultIfNotInvoked(get()); 
                } catch (InterruptedException e) {
                    ..
                } catch (ExecutionException e) {
                    ..
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

构造方法里做了三件事:初始化handler,这个handler默认是主线程的handler、实例化mWorker,这是真正的执行任务者,实例化mFuture,用来对mWorker进行管理,来处理多个任务(默认的话,多个任务是串行处理,按照传入的顺序)

构造完了AsyncTask对象后,就调用了execute()方法执行任务

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) {
            switch (mStatus) {
                case RUNNING:
                    .. // 异常
                case FINISHED:
                    .. // 异常
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute(); // onPreExecute()在这里被调用,所以是它在主线程里被调用的

        mWorker.mParams = params; // 给worker传入参数
        exec.execute(mFuture); // 执行的是mFuture对象

        return this;
    }

可以看到任务是在sDefaultExecutor上执行的,而sDefalutExecutor是一个串行处理器,它的定义如下

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

所以我们要看一看串行处理器是怎么执行任务的

SerialExecutor#execute()

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

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                // offer方法把对象放到队尾
                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);
            }
        }
    }

execute()方法就是把传进来的runnable对象(这里是mFuture)放到了mTasks队列队尾,然后判断mActive,也就是当前执行的线程是否是空,是空的话,调用scheduleNext()方法从队列队首获取元素,放到THREAD_POOL_EXECUTOR中执行。

关于THREAD_POOL_EXECUTOR的定义如下

    public static final Executor THREAD_POOL_EXECUTOR;

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

这就是个线程池,里面的参数都是异步任务自己设定的,代码如下

 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); // 最大并行线程数,至少是2个线程
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; // 线程池容量
    private static final int KEEP_ALIVE_SECONDS = 30; // 每个线程最多执行30秒

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            // 构造线程时,直接new
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128); // 线程队列模型是阻塞链表,容量128
        

关于线程池怎么工作,请参加文章安卓开发学习之线程池源码解析

执行一个线程,就是执行它的run()方法,而这里的mFuture线程是FutureTask类,所以就要看看FutureTask类的run()方法的内容

FutureTask#run()方法

    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable; // callable就是构造方法里传进来的worker
            if (c != null && state == NEW) { // 没有执行前,state就是NEW
                V result;
                boolean ran;
                try {
                    result = c.call(); // 调用worker的call()方法
                    ran = true; // 设置标志位
                } catch (Throwable ex) {
                    .. // 异常
                }
                if (ran)
                    set(result); // 设置结果,不过AsyncTask处理结果是在worker的call()方法,这里没什么用处
            }
        } finally {
            ...
        }
    }

原来worker的call()方法是在这儿被调用的,我们回到AsyncTask的构造方法里看看worker的call()方法,会知道它执行了doInBackground()后,在finally里进行了结果的处理,也就是调用AsyncTask的postResult()方法

AsyncTask#postResult()方法

    private Result postResult(Result result) {
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result)); 
                // 把AsyncTask自己和任务执行结果封装成AsyncTaskResult对象
                // 其中任务执行结果是作为数组保存的
        message.sendToTarget();
        return result;
    }

    private Handler getHandler() {
        return mHandler; 
        // 在AsyncTask构造方法里,mHandler被赋值成了sHandler,因为我们传进去的callbackLooper默认是null
    }

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper); // looper是主线程的looper
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // result.mTask就是AsyncTask自己,mData[0]就是要处理的结果
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS: // 刷新进度条
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result); // 执行onPostExecute()处理结果
        }
        mStatus = Status.FINISHED;
    }

如此,从任务执行前,到任务执行时,再到结果处理,整个过程都清楚了。接下来我们看进度条的更新调用

AsyncTask#publishProgress()方法

    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

这个方法需要我们在doInBackground()里调用的,不调用是不会更新进度条的。关于handler如何处理MESSAGE_POST_PROGRESS消息,请参见上文。

结语

关于异步任务的处理流程源码的阅读就是这样。

猜你喜欢

转载自blog.csdn.net/qq_37475168/article/details/81197583