AsyncTask 原理

AsyncTask是Android提供的一个工具,可以用来处理轻量级的异步任务,AsyncTask是一个非常经典的模板模式的实现,模板模式:大概就是说,执行一次exeute,可以依次执行一些可以被你重写的方法。就像AsyncTask,每次执行exeute,都会依次执行onPreExecute,doInBackground,onPostExecute,这三个方法只有doInBackground会在异步执行,onPostExecute会在主线程执行,同时在异步执行的过程中,可以选择性地执行onProgressUpdate,来告诉主线程,后台已经执行到了那个步骤。

使用方法

看一下这个类定定义:
public abstract class AsyncTask<Params, Progress, Result>
可以看到这时一个抽象类,同时通过泛型编程的方式可以定义三个参数Params, Progress, Result,分别对应着可以传入doInBackground,onProgressUpdate,onPostExecute的参数,Result同时也是doInBackground的返回值

    protected abstract Result doInBackground(Params... params);
    protected void onProgressUpdate(Progress... values) {
    }
    protected void onPostExecute(Result result) {
    }

同时也可以看到doInBackground是一个抽象方法,使用时必须实现它,而其他的则是可选的。
简单使用

        new AsyncTask<String, Void, JSONObject>() {
            @Override
            protected JSONObject doInBackground(String... params) {
                return getContactsByPhoneNumber(resolver, params[0]);
            }

            @Override
            protected void onPostExecute(JSONObject result) {
                request.getCallback().callback(new Response(Response.CODE_SUCCESS, result));
            }
        }.execute(phoneNumber);

这个例子也是非常简单,主要也是可以看一下各个参数间的关系,它可以在主线程和后台线程之间传递一些对象。

线程池

既然要后台线程执行,那必不可少的就是线程了,AsyncTask就有两个或者说是一个线程池,通过static的方式,保证一个进程内只有一份。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
    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) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            // 将runable加入到队列当中
            if (mActive == null) {
                //如果mActive为空,则执行下一个runable
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                // mActive为runable的第一个,并且只用THREAD_POOL_EXECUTOR执行它。
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

通过看SerialExecutor的定义发现,它其实是THREAD_POOL_EXECUTOR的封装,实际使用的还是THREAD_POOL_EXECUTOR,并且可以看到它维护了一个Runable的队列,真正在执行的Runable只有一个。也就是说使用SERIAL_EXECUTOR其实就是一个单线程池

再来看THREAD_POOL_EXECUTOR

/**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    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;
    }

这时一个真的线程池了,具体的就不解释了。其实在默认情况下都是使用的sDefaultExecutor,所以在你不指定线程池的情况下,你就把他当做一个单线程池来用,同时需要注意的是在一个进程内,这个线程池都是这一个,这意味这你要小心,你的异步任务可能都在排队,所以这个只适用于轻量级的任务,你要保证后台的任务不会花太长的时间,也不能有阻塞的风险,不然的话就会导致其他任务的延后或者阻塞。

执行过程

接下来看看exeute

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    // 根据注释,这个方法必须在UI线程执行,也可以看到就是用的sDefaultExecutor,
    // 同时不知道为何,既然只能在UI线程执行为何sDefaultExecutor 声明为了volatile,
    // 这是我的一个疑问吧。

    @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)");
            }
        }
        // 在执行前,状态必须是Status.PENDING,

        mStatus = Status.RUNNING;

        onPreExecute();
        // 执行onPreExecute()

        mWorker.mParams = params;
        // 赋值params
        exec.execute(mFuture);
        用线程池执行mFuture

        return this;
    }

这个mFuture和mWorker到底是什么的,应该很容易猜到 Callable和FutureTask

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    // 两个AtomicBoolean,保证线程安全,代表任务是否取消,后台任务是否执行了

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                // 可以看到返回值是Result,FutureTask的get()方法可以得到,防止因意外不执行
                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);
                    // 会将结果post到主线程
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                // 重写了done方法,就是说如果一些原因,后台线程线程没能执行,我们也要postResultIfNotInvoked
                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);
                }
            }
        };

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            // 如果WorkerRunnable未能执行
            postResult(result);
        }
    }

        private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    // 可以看到,postResult,就是向这个Handler发送一个messge,这应该是android线程间交互的最简单的方式之一,这样我们就能吧result发回到主线程。

最后看看这个handler

private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
            // 使用主线程的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]);
                    // 调用finsih
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
            // 如果已经cancel,调用onCancelled() 一个可重写方法
        } else {
            onPostExecute(result);
            // finish后onPostExecute
        }
        mStatus = Status.FINISHED;
    }

    // 可以看到它还处理一个message:MESSAGE_POST_PROGRESS, 可以猜到了就是那个onProgressUpdate。
    // 我们只需要在doBackground中执行publishProgress
    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
    // 这样就可以把一些中间过程post到UI线程

到这里AsyncTask的原理就差不多介绍完了,还有小细节就不多说了,它其实就是用了FutureTask来执行后台任务,并且通过一个handler来实现与主线程的交互,可以看到整个源码也是非常的少,调用过程非常清晰而且容易理解。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值