AsyncTask的使用&源码详解

AsyncTask源码详解

AsyncTask是Android提供的异步执行任务的工具,上层使用了串行任务调度器保证单任务执行,底层使用了线程池实现,另外使用了FutureTask的特性,提供了终止任务的方法。

一、AsyncTask使用方法

1.自定义AsyncTask
继承AsyncTask,重写回调方法
写一个可以计算斐波纳契数列和的异步任务,耗时久一点
public class FibonacciTask extends AsyncTask<Integer, Float, Integer> {
    private static final String TAG = "FibonacciTask";

    @Override
    protected Integer doInBackground(Integer... integers) {
        int sum = 0, length = integers.length;
        for(int i = 0 ; i < length; i++) {
            sum += fn(integers[i]);
            publishProgress(((float)(i + 1) / (float)length) * 100);
            Log.d(TAG, "doInBackground " + printThread());
        }
        return sum;
    }

    @Override
    protected void onPreExecute() {
        // super.onPreExecute(); 空方法
        // 这里可以做一些初始化,打印一下调用就好
        Log.d(TAG, "onPreExecute" +  printThread());
        printThread();
    }

    @Override
    protected void onPostExecute(Integer integer) {
        // super.onPostExecute(integer); 空方法
        // 打印一下结果
        Log.d(TAG, "onPostExecute: " + integer + printThread());
    }

    @Override
    protected void onProgressUpdate(Float... values) {
        // super.onProgressUpdate(values); 空方法
        // 打印一下进度
        Log.d(TAG, "onProgressUpdate: " + values[0] + printThread());
    }

    @Override
    protected void onCancelled(Integer integer) {
        // 父类 调了onCancelled(),onCancelled()为空方法
        // super.onCancelled(integer);
        // 打印一下调用
        Log.d(TAG, "onCancelled("+ integer +")" + printThread());
    }

    @Override
    protected void onCancelled() {
        // super.onCancelled(); 空方法
        // 打印一下调用
        Log.d(TAG, "onCancelled()" + printThread());
    }

    private int fn(int n) {
        if(n == 1 || n == 2) {
            return 1;
        }
        return fn(n - 1) + fn(n - 2);
    }

    private String printThread() {
        return " threadId:" + Thread.currentThread().getId();
    }
}
2.创建对象,执行任务
创建任务对象,执行任务
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: threadId:" + Thread.currentThread().getId());
        // 创建一个异步任务对象
        final FibonacciTask task = new FibonacciTask();
        // 开始执行
        task.execute(10, 11, 15, 30, 40);
        Button button = findViewById(R.id.cancel);
        // 点击取消任务
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 这个boolean参数表示是否中断正在执行的任务
                task.cancel(true);
            }
        });
    }
}
结果如下:
2020-05-19 23:18:59.862 2876-2876/? D/MainActivity: onCreate: threadId:2
2020-05-19 23:18:59.862 2876-2876/? D/FibonacciTask: onPreExecute threadId:2
2020-05-19 23:19:01.416 2876-2903/comlscag.learn D/FibonacciTask: doInBackground  threadId:200
2020-05-19 23:19:01.416 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 20.0 threadId:2
2020-05-19 23:19:03.854 2876-2903/comlscag.learn D/FibonacciTask: doInBackground  threadId:200
2020-05-19 23:19:03.854 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 40.0 threadId:2
2020-05-19 23:19:07.748 2876-2903/comlscag.learn D/FibonacciTask: doInBackground  threadId:200
2020-05-19 23:19:07.748 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 60.000004 threadId:2
2020-05-19 23:19:14.033 2876-2903/comlscag.learn D/FibonacciTask: doInBackground  threadId:200
2020-05-19 23:19:14.033 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 80.0 threadId:2
2020-05-19 23:19:24.213 2876-2903/comlscag.learn D/FibonacciTask: doInBackground  threadId:200
2020-05-19 23:19:24.213 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 100.0 threadId:2
2020-05-19 23:19:24.213 2876-2876/comlscag.learn D/FibonacciTask: onPostExecute: 1670731762 threadId:2

可以看到除了doInBackground以外的方法都是在主线程执行的。

二、Async源码详解

2.1 创建任务
2.1.1 构造方法
    public AsyncTask() {
        // 调用AsyncTask(@Nullable Looper callbackLooper),传入Looper为空
        this((Looper) null);
    }

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

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     * 必须在主线程调用?为什么?
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        // 默认的构造方法looper传进来是null,这里会调getMainHandler() 获取handler,
        // 如果反射传进来了指定的looper,并且不是主线程的looper,则会将handler指向对应线程(原理和HandlerThread一样)
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        // 创建一个WorkerRunnable对象,它是任务的实际执行者,详见2.2.4
        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
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };
        // 创建一个FutureTask对象,传入刚才创建的worker,
        // 可以看到这里重写了done方法,FutureTask的介绍详见2.2.5
        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);
                }
            }
        };
    }

可以看到,每个异步任务对象都会实例化一个mWorker对象和一个mFuture对象,mWorker是任务的实际执行者,mFuture提供了对任务管理(触发、调度、取消、传递结果)等功能。

2.2 执行任务
2.2.1 串行执行器执行任务
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        // sDefaultExecutor详见2.2.2
        return executeOnExecutor(sDefaultExecutor, params);
    }

    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        // 执行过execute的异步任务对象无法再执行第二次
        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();
        // 给worker设置参数
        mWorker.mParams = params;
        // 串行执行器执行任务
        exec.execute(mFuture);
        return this;
    }
2.2.2 串行控制器
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    private static class SerialExecutor implements Executor {
        // 维护了一个任务队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
       // 执行方法,将任务入队,如果当前没有执行任务,就开始调用线程池执行,否则等当前任务执行完成才执行下一个任务,典型的串行控制器,多个异步任务执行execute时是串行执行的
        public synchronized void execute(final Runnable r) {
            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);
            }
        }
    }
2.2.3 线程池执行器
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 核心线程数:可用cpu核心数 <= 3为2个;可用cpu核心数 >= 4为4个
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    // 线程池最大容量:cpu核心数*2 +1
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    // 非核心线程最大存活时间:30秒
    private static final int KEEP_ALIVE_SECONDS = 30;
    // 线程工厂:给每个线程按顺序指定了name
    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());
        }
    };
    // 任务队列
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);   

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

可以看到线程池是支持多个任务并行执行的,但由于串行控制器的存在,实际上多个异步任务是串行执行的,当然,可以通过反射hook掉串行执行器,实现并行的异步任务。

串行控制器会依次将任务队列中的任务交给线程池执行,执行的任务正是创建AsyncTask实例时构造的mFuture对象,mFuture对象又持有了WorkRunnable对象mWorker,接下来看看这两个对象是如何工作的。

2.2.4 WorkRunnable 和 Callable
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }

WorkerRunnable是AsyncTask的静态内部类,实现了Callable接口
根据1.1中创建的匿名类可以看到WorkerRunnable会持有doInBackground的参数mParams,
并且返回处理结果result

2.2.5 FutureTask

FutureTask间接实现了Runnable接口,在被线程池调度时会执行run方法。

    // 异步任务中创建mFuture的构造方法
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    // FutureTask中done是个空方法
    protected void done() { }
    
    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    protected void set(V v) {
        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
            outcome = v;
            U.putOrderedInt(this, STATE, NORMAL); // final state
            finishCompletion();
        }
    }

其run方法判断了任务状态,如果不是新任务不会被执行,同时用CAS的方法记录了当前执行任务线程到FutureTask的runner字段,接着调用了mWorker的run方法真正执行任务,如果任务被成功执行,则会调set方法修改当前任务状态,并调finishCompletion结束任务。

2.2.6 任务取消

最后看一下AsyncTask的取消过程

    // AsyncTask.cancel
    public final boolean cancel(boolean mayInterruptIfRunning) {
        // 设置取消状态,并执行mFuture的cancel方法
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }
    // FutureTask.cancel
    public boolean cancel(boolean mayInterruptIfRunning) {
        // 判断并修改任务状态,如果设置cancel是允许中断当前执行任务的,则会中断正在执行的线程
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            // 最终调用finishCompletion结束任务
            finishCompletion();
        }
        return true;
    }

    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        // 可以看到这里调了done方法,可以回到2.1.1的构造方法中看到,done方法会将已经执行的结果传递出去
        done();
        callable = null;        // to reduce footprint
    }

AsyncTask的任务取消操作是基于FutureTask的取消操作执行的,提供了中断当前任务\不中断当前任务,两种取消方法,并且会在取消时返回已执行结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值