美文网首页一些收藏
AsyncTask源码学习

AsyncTask源码学习

作者: 慕北人 | 来源:发表于2020-03-14 00:39 被阅读0次

AsyncTask源码学习

AsyncTask的实现原理是通过Java中的线程池来的。

一、重要属性

AsyncTask中又三个线程池的成员变量:

  • THREAD_POOL_EXECUTOR:这是一个public修饰的静态成员,是Executor常量
  • SERIAL_EXECUTOR:这是一个public修饰的静态成员,是Executor常量,只不过在定义的同时直接初始化为了内部类SerialExecutor对象,该类实现类任务的按序执行
  • sDefaultExecutor:这是一个private修饰的静态成员,volatile修饰,而且默认值为SERIAL_EXECUTOR

关于线程池配置的一些参数:

  • CORE_POOL_SIZE:核心池的大小,值为Math.max(2, Math.min(CPU_COUNT - 1, 4))
  • MAXIMUM_POOL_SIZE:线程池最大容量,值为CPU_COUNT * 2 + 1
  • KEEP_ALIVE_SECONDS:空闲线程的存活时间,值为30s
  • sTreadFactory:生成Thread对象的工厂,唯一干的事情就是记录线程创建的数目,并且按照他们的顺序为他们命名
  • sPoolWorkQueue:任务队列,容量为128

AsyncTask切换线程实现前台和后台线程分离的原理在于使用了Handler和Looper的搭配,我们来看看Looper和Handler的相关变量:

  • mHandler:是一个private修饰的Handler常量,而AsyncTask内部的私有方法getHandler就是返回的该成员
  • sHandler:是一个private修饰的静态InternalHandler常量,其所绑定的Looper为主线程的Looper,而AsyncTask内部的私有方法getMainHandler会将该Handler初始化,并且返回的该成员

InternalHandler的实现

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  
                ---------- 重点 1 ----------
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                ------------ 重点 2 -------------
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}  

可见,该Handler的handleMessage方法已经实现了对两种Message的处理;注意,在重点1和重点2处的result.mTask实际就是指正在使用的AsyncTask对象,这里也正好展示了AsyncTask的两个方法finish和onProgressUpdate的调用时机

二、构造函数

AsyncTask有三个构造函数,但终究还是回调的AsyncTask(Looper callbackLooper)这个构造函数:

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

public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
}   

AsyncTask(Looper):

public AsyncTask(@Nullable Looper callbackLooper) {  

    --------------- 重点 1 ---------------
    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

        ---------------- 重点 2 -------------
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
        ---------------- 重点 3 ------------
                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);
            }
        }
    };
}  

首先看注释中的重点 1

  • 执行初始化mHandler的功能,调用无参构造器或者传递的参数为null的话,那么mHandler就会被赋值为getMainHandler的返回值,上文中说这个方法的返回值是sHandler,而sHandler是一个绑定到主线程的Looper上的InternalHandler,也就是说mHandler处理Message发生在主线程。因此在大多情况下我们在主线程下创建AsyncTask时,只需要默认构造器就好。

再看mWorker的初始化:

  • 重点2展示了我们在使用AsyncTask的时候需要重写的方法,doInBackground
  • 重点3的功能是将Result交给mHandler处理,所以这个方法才是后台得到的结果可以传到其他的线程去使用的关键:

postResult:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}    

可见,该方法实现了在try块中调用doInBackground执行后台任务,待其执行完毕,得到result之后,在finally块中通过postResult方法将后台线程获取到的结果交给前台线程使用,真实很巧妙优雅的设计。

三、工作流程

1. 入口方法execute(Progress...)方法

该方法的实现只是一个简单的回调:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}  

executeOnExecutor方法

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;

    ----------- 重点 1 -----------
    onPreExecute();

    mWorker.mParams = params;
    -------------- 重点 2 --------------
    exec.execute(mFuture);

    return this;
}  

注意,调用该方法的时候exec参数的值为sDefaultExecutor,而上文中说道,sDefaultExecutor的值为SerialExecutor对象,所以说AsyncTask处理任务是按顺序处理的

  • 重点1处又出现了一个我们在使用时可以选择重写的一个方法的调用,而该方法调用发生在exec.execute之前,后者里面会调用mWorker中的call方法触发doInBackground方法;我们可以在onPreExecute方法中做一些准备工作

2. 其他方法

finish方法

当我们使用主线程Looper作为Looper的时候,该方法发生在handler处理POST_RESULT消息的时候:

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}  

他会根据当前AsyncTask是否取消调用不同的方法,当没有取消时,会调用onPostResult方法,因此我们需要重写onPostResult方法来更新我们的UI

publishProgress方法

该方法可以将progress消息通知到Handler中:

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

我们上文中展示过,Handler在处理progress时间时会调用onProgressUpdate方法,所以我们可以重写onProgressUpdate方法来展示进度条等

相关文章

  • AsyncTask源码学习

    AsyncTask源码学习 AsyncTask的实现原理是通过Java中的线程池来的。 一、重要属性 AsyncT...

  • Android AsyncTask 源码解析

    标签:Android AsyncTask 源码解析 1.关于AsyncTask 1.1 什么是AsyncTask?...

  • AsyncTask源码学习

    首先回顾一下AsyncTask的用法,他是一个抽象类,需要我们继承实现一些方法,常用的方法如下: 另外AsyncT...

  • AsyncTask 源码学习

    AsyncTask 是系统提供一种用来执行异步任务的一个工具类,也是我们一直接触和使用比较多的一个。只有我们了解了...

  • AsyncTask异步任务的源码详细解析

    1、AsyncTask基本使用: 2、AsyncTask源码阅读,点击asyncTask.execute("www...

  • Android源码之AsyncTask

    参考 本文源码版本:Pie 9.0.0_r3 在线源码地址:AsyncTask.java 1 AsyncTask简...

  • Android源码解析-Asynctask

    android源码分析-AsyncTask 我们一般创建一个AsyncTask的任务代码如下: 下面开始分析源码:...

  • AsyncTask异步任务类

    目录介绍 01.先看下AsyncTask用法 02.AsyncTask源码深入分析2.1 构造方法源码分析2.2 ...

  • Android源码学习--AsyncTask

    AsyncTask官方介绍与说明 Android主线程中无法执行耗时操作,这要求开发者在自定义的工作线程中完成耗时...

  • AsyncTask源码学习总结

    前言 AsyncTask作为Android常用的异步消息机制,内部核心原理其实就是Handler。本小记不对Asy...

网友评论

    本文标题:AsyncTask源码学习

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