AsyncTask入门

构造方法

        在子线程中执行操作,并在主线程中处理操作结果。

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {//WorkerRunnable实现了Callback接口
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(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);
                }
            }
        };
    }
        生成一个Callback类型的mWorker,它内容有一个类型为Params[]的变量mParams;一个FutureTask类型的mFuture。

executeOnExecutor

        调用execute()时会执行到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;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }
        可以看出,首先进行了判断,然后调用onPreExecute(),再将传入的params赋值到mWorker的变量mParams。其中exec为execute传入的sDefaultExecutor。其具体实现如下:
    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();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
        在execute中,先会将一个Runnable对象添加到mTask中,这个对象的run()方法中会调用mFuture.run()。因此,只要执行到mTask中的对象,就会执行到当前的AsyncTask中的mFuture。

        添加完后会对mActive进行判断,在执行第一个AsyncTask时,mActive==null是成立的,从而开始执行scheduleNext(),在该方法中会从mTask中取出一个对象执行其run()方法,这也就是开始执行mFuture.run()了。在每一个run()执行结束会接着调用scheduleNext(),这就形成了一个循环,保证了mTask中的所有对象都会被执行到。

        在scheduleNext()中,会在线程池中执行mFuture,因此mFuture的run()方法执行在线程池中。

        从这里也可以发现调用AsyncTask#execute()并不会立即执行该task,而是先将其添加到一个列表中,等它前面的所有task执行完毕之后才执行它。这也说明了:AsyncTask是串行执行的。如果想要立即执行该task,应该直接调用AsyncTask#executeOnExecutor()。

        对于mTasks的类型,可参数集合中的ArrayDeque。

WorkRunnable#call

        上面知道最终会在线程池中执行mFuture的run()方法,而该方法又会调用与mFuture关联的Callback#call(),即会调用mWork中的call()方法。其代码如下:

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };
        这里终于调用了doInBackground(),而且是在线程池中调用的该方法,将其返回值传递到了postResult()中。

postResult()

其内部只是通过handler将结果发送一个Message。如下:

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
而在该getHandler()的handleMessage()中会调用AsyncTask#finish(),如下:
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

        这里终于看到了onPostExecute()。而且它是在某个handler的handleMessage()方法中进行的调用。因此,onPostExecute()的执行线程将与getHandler返回的Handler的Looper直接相关:如果Looper是主线程的Looper,那么onPostExecute()将执行在UI线程中,否则将在子线程中执行的。

InternalHandler

        上面的postResult()中调用了getHandler()方法,该方法返回的就是一个InternalHandler对象。其代码如下:

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

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

        非常开心,在构造方法中传入的是主线程的Looper,这就保证了onPostExecute()会执行在主线程。

cancel()

        使用线程时,总会担心因为线程的原因导致内存泄漏(如Activity本身已经finish()了,但其内部仍有线程在执行,导致activity无法被回收)。AsyncTask提供了cancel方法,但这个方法并不是能瞬间停止线程的。如下:

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }
        第一句:将mCancelled设置为true,这是一个AtomicBoolean类型的变量,它是原子性的boolean,也赋值过程中不会被线程调度所打断,但它并不具备可见性(一个线程的修改对另外的线程都可见)。
        第二句:调用了FutureTask#cancel()方法,其内部又调用了Thread#intercept(),这个只是发送一个停止当前线程的请求,并不能完全停止线程。因此,cancel并不会立即停止当前正在执行的线程。

        为解决该问题,需要在doInBackground()中不断的满足是否被cancel掉了,如果是就不再执行doInbackground,这样线程才会被停止。

优先级

        在AsyncTask中有一句:

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        这就是设置执行mWorker对象的线程的优先级。从这里可以看出,它的优先级是background(值为10,最低的优先级是19,值越大优先级越低)。对这个优先级的解释为:比正常的优先级要低,从而打断UI操作的机会变小。因此,AsyncTask打断UI操作的可能性比较小。
        但在HandlerThread中,设置的是优先级是DEFAULE(值为0),而标准的前台线程的优先级是-2,所以从这里可以看出HandlerThread的优先级要远远高于AsyncTask,是介于后台线程与前台线程之间的。

总结

        1,AsyncTask是串行执行的,如果想在立即执行需要调用executeOnExecutor()而不是execute()。

        2,一个AsyncTask只能调用一次executeOnExecutor,无论是直接调用还是通过execute()调用。这个可以通过executeOnExecutor的源码判断出来。

        3,由于在低版本(上面代码来源于API23)对于InternalHandler的定义方法不同,并且直接声明了一个静态的InternalHandler对象sHandler,所以为保证onPostExecute()正确地执行在UI线程中,并且在主线程中加载AsyncTask类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值