Android AsyncTask 源码解析

是什么东西?

顾名思义,异步任务,就是说我们可以让我们异步执行任务,不过通常使用它是为了异步执行,主线程更新UI,我们都知道,Android 的UI更新操作,都会检查是否是主线程,如果不是的话就会报出异常,这一步是在ViewRootImpl里面做的,这里就不多说了。在使用的时候,我们只需要将后台处理的代码写在doInBackground,更新UI的工作写在onPostExecute就行了,就可以轻松实现一个线程切换,更新UI的效果。那这里你可能会问。为什么不用Handler,我也许会告诉你,使用 AsyncTask 有很多好处,待会会慢慢告诉你,你也可以根据源码,一探究竟。

前世今生

没有继承自任何东西,Object 除外,使用了模板定义,Params 代表你要传的参数类型,Progress 代表更新数据类型,Result 是任务执行玩返回数据类型。

public abstract class AsyncTask<Params, Progress, Result> {}

使用场景

只要需要开启子线程的都可以使用它。在项目中,随便 new Thread 并不是一个好习惯,滥用不说,很有可能造成内存泄露

实现原理大白话

有两个东西很关键,一个是线程池,一个是 Handler,线程池负责执行任务, Handler 负责通知,说道这,聪明的你大概猜到了实现方式,但这并不够,我们需要细细的品味这个类是如何写成的。

源码解析

属性

通过使用 Runtime 对象获取可用的cpu 个数,在创建线程池时创建合适的线程数量,线程池的参数主要是核心线程数,这里最小值2, 最大值4,当处理器个数为4时,创建3个核心线程数,最大线程数为 cpu个数的两倍 + 1,关于核心线程数,最大线程数,大家可自行去了解作用,以后创建线程池,大家可要记住了,以这样创建线程池数是比较合理的。KeepAliveTime 是线程存活时间,超过这个时间的线程要被回收,至于哪一些线程,待会再说

    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));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

静态线程工厂,在类加载是就会被创建,里面使用了AtomicInteger 用来计数。使用了LinkedBlockingQueue作为任务队列

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

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

使用静态代码块初始化线程池,参数为以上分析的数据,注意,allowCoreThreadTimeOut 设置为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;
    }

还有一个重头戏,单任务执行器,默认不是用上面的线程池执行任务,而是使用序列执行器执行任务,意识就是,同一时刻只能执行一个任务,注意这些都是静态的,也就是说,一个进程,不管你新建了多少个 Task对象,他也只能单个任务执行,这样就很好的管理了资源,那他是如何做到单任务执行的呢,实现方式可以说是既巧妙又无语,且看注释

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static class SerialExecutor implements Executor {
        // 保存任务
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            // 新任务进来,不执行,而是使用匿名内部类创建一个Task加到任务队列里,
            // 当这个执行完的时候,才会去调用下一个任务,就做到了单任务执行。
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            // 默认先
            if (mActive == null) {
                scheduleNext();
            }
        }

        // 这里是真正去执行的
        // 注意,使用到了 synchronized 的可重入特性!
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

一些静态的变量基本看完了,下面来看一下构造函数,有点长

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        // 首先获取 Handler 对象,这里有主线程 Handler 和子线程Handler 之分
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        // 异步执行的,实现了callable接口
        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 {
                    // 执行完,这里还是在子线程
                    postResult(result);
                }
                return result;
            }
        };

        // FutureTask 对象,封装Callable 对象
        mFuture = new FutureTask<Result>(mWorker) {
            // 结束时调用
            @Override
            protected void done() {
                try {
                    // 如果没有被调用的话,通过get获取结果
                    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);
                }
            }
        };
    }

执行完以后,使用Handler 进行通知,注意,这里将结果装入Message对象中,直接发送。一个小技巧,我们在发送消息是尽可能使用 obtainMessage 获取Message对象要比new一个好得多。

    // 返回结果,使用handler
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

那执行入口呢? MainThread 代表主线程执行

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    @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();

        mWorker.mParams = params;
        // 执行
        exec.execute(mFuture);

        return this;
    }

一些我们可能需要实现的函数

    //   我们将后台逻辑写在这里
    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    @MainThread
    protected void onPreExecute() {
    }
    // 执行完回调
    @MainThread
    protected void onPostExecute(Result result) {
    }
    // 如果有进度条更新
    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }

    @MainThread
    protected void onCancelled() {
    }

如何更新进度条?只需要在 doInBackground 中调用即可,将参数传入,使用handler机制

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

Handler 处理消息的地方,静态类

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

当然,你也可以取消任务,不过只能取消还没执行的任务,底层是调用 thread.interrupt 方法,简单粗暴,关于他的使用,可以写一堆东西来说,这里暂且不展开说

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

当然,如果不要于UI交互,你也可以使用这个执行后台逻辑,直接调用executeOnExecutor,使用静态的execute提交,这里是单任务的

public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }

当然,也可以多任务一起执行,调用executeOnExecutor时指定内部的线程池即可AsyncTask.THREAD_POOL_EXECUTOR

总结

我们了解这AsyncTask这个类,大致知道了他是怎么实现了,如果要进一步了解的话,线程池,锁这些东西必不可少的~

如有错误,欢迎讨论

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值