AsyncTask源码分析

AsyncTask

AsyncTask能够更方便地在子线程中更新UI元素。

AsyncTask enables proper and easy use ofthe UI thread.

AsyncTask是Android提供的轻量级的异步类。

Android之所以有AsyncTask和Handler都是为了不阻塞ui线程,且ui的更新只能在主线程完成,因此异步处理时不可避免的。

首先我们讲下AsyncTask的使用

public abstractclass AsyncTask<Params, Progress, Result>

AsyncTask是一个抽象类,要使用AsyncyTask我们要提供三个泛型参数,并重载几个方法

AsyncTask定义了三种泛型类型 Params,Progress和Result。

•Params 启动任务执行的输入参数,比如HTTP请求的URL。

•Progress 后台任务执行的百分比。

•Result 后台执行任务最终返回的结果,比如String。

使用过AsyncTask的同学都知道我们经常使用这四个方法

onPreExecute():UI线程

    后台任务执行之前调用,用来进行一些UI上的初始化操作,比如显示一个进度条对话框等。

doInBackground(Params...) (必须):后台进程

    后台任务执行时,负责处理所有耗时任务。

onProgressUpdate(Progress...):UI线程

    后台任务执行时,反馈后台任务的执行进度,进度条的改变。

onPostExecute(Result) (必须):UI线程

当然还有一个onCancelled();可以用来取消当前任务

        后台任务执行完毕时调用,用返回数据来进行一些UI的操作,比如显示后台任务执行结果。

使用AsyncTask要注意的几点是

1.      AsyncTask类必须在UI线程中加载

2.      AsyncTask的实例必须在UI线程中创建

3.      AsyncTask.execute()必须在UI 线程中调用

4.      不要手动调用doInBackground()上述的几个方法

5.      AsyncTask.execute()只能调用一次

  AsyncTask的执行过程

我们使用AsyncTask都是通过execute(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;

        onPreExecute();

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

        return this;
    }
在这里面有一个status标志,如果status==Pending的才会正常进行,如果为Running或者FINISHED就会抛出异常,这也就是AsyncTask只能调用一次的原因,多次调用就会报错,在初始化之后就进入了我们的四大常用方法之一的onPreExecute()(进行UI的初始化)了,在这里面进行一些UI的初始化,当前线程依然处在UI线程,之后出现了两个对象一个是mWork,一个是mFuture,而在AsyncTask的构造函数中就做了两件事

1.初始化mwork2.初始化mFuture。

 	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);
            }
        };
首先说说这个mWork,他是WordRunnable的实例,WorkRunnable是一个抽象类,实现了Callable接口, 在初始化化他的时候就要实现call方法,在call中首先设置mTaskInvoked为true表示在调用,而call方法中就有另一个四大方法之一的doInbackground()(进行耗时操作);,并且将返回值作为参数给postResult方法,但是call()在这个时候还没有执行,只是初始化了mWork。

那么postResult是干什么的,

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

        在源码中我们可以看到了异步消息机制,这里是通过Message发送信息,看到这基本就可以想到肯定在主线程(UI线程)中有一个handler,并且通过handlerMessage方法等待消息的接收,

 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;
            }
        }
    }
这里就有一个InternalHandler,这里处理了两种结果,一种是MESSAGE_POST_RESULT,如果message传的是这个标志,则意味着结束,也就是AsyncTask.this.finish();如果是MESSAGE_POST_PROGRESS,则意味着正在执行过程中,那么就出现了我们四大方法之一的onProgressUpdate()(更新UI,耗时任务的进度);

  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
在finish还有要一个常用的第五个方法,那就是onCanelled(),如果我们调用了cancel就会执行onCalled回调,如果没有取消即正常调用的话,那就是最后一个四大方法之一的onProgressExcute()将任务结果更新在UI;最后将状态设置为FINISHED;

说了这么多mWork终于讲完了,那么现在看下mFuture,

 	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);
                }
            }
        };
mFuture是将mwork作为参数的,并且复写了done方法

在done方法中调用了postResultIfNotInvokded(get());get()就是获取mWork中call的返回值,然后将结果作为PostResult()方法的参数使用,

  但是说了这么多,mWork和mFuture都只是初始化了,还没有真正执行,

他的执行就是在

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);
第四行代码。

这里就是一个SerialExcutor(串行执行)的实例exec,

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

在SerialExcutor内部就是一个任务队列,以及一个execute(Runnable runnable)函数,

将runnable放入mTasks队尾,判断当前的Runnable执行实例mActive,如果为空,则调用scheduleNext,而scheduleNext则将队列头出列,如果任务不为空,交给线程池进行执行任务。

听到线程池,那有些人在想,那AsyncTask是可以通知执行好多个任务吗,也就是并行的吗?但是不是说AsyncTask是串行的吗?

其实AsyncTask是串行的,比如当前有10个任务同时执行了execute,方法,第一个任务入队,然后因为mActive目前是null则执行scheduleNext,则将任务出队并赋值给mActive,然后交给线程池去执行。然后第二个任务进来了,但是mActive此时不是null了,所以执行不了sceduleNext,所以只能等待,而真正执行下一个任务的时机是在线程池执行完第一个任务后,调用了Runnable中的finnaly方法,在这里执行了scheduleNext方法,所以虽然内部有一个线程池,但是其实调用的过程还是串行的,一个接一个,相当于单线程。


        AsyncTask缺陷:

  可以分为两个部分说,在3.0以前,最大支持128个线程的并发,10个任务的等待。也就是容易出现并发错误。所以138个任务可以并发执行,但是139个任务就会出错,那是因为在阻塞队列(10)中塞满时,会调用一个reject()放在,这个会拒绝执行这个任务,并且抛出异常。3.0以后,无论有多少任务,都会在其内部单线程执行;

        除了缺陷我在说说最开始说的那些AsyncTask的规则

        1.AsyncTask 类必须在UI线程中被加载

       因为AsyncTask有一个静态内部类InternalHandler,这里有handlerMessage方法,要处理ui更新,所以该hanlder要放在UI线程,因为是静态内部类,所以在类加载的时候就进行初始化了,所以AsyncTask得放在UI线程加载。

2.AsyncTask的实例必须在UI线程中创建

AsyncTask内部的onProgressUpdate()方法和onPostExecute()都是些更新UI的,所以都得处在UI进程,

在哪个线程中创建onPostExecute()方法就会在哪个线程中执行,所以AsyncTask的实例也必须在UI线程中创建。

3.AsyncTask.execute()必须在UI 线程中调用

AysncTask的execute()方法调用了onPreExecute()方法,该方法在task开始前在UI线程进行若干的准

备工作,所以必须处在UI线程中。

4.不要手动调用doInBackground()上述的几个方法

这几个方法都是些回调方法,只需要实现或重写即可

5.AsyncTask.execute()只能调用一次

首先,是源码在execute()中设置了Status状态,在task开始后Status就会变成RUNNING,就会抛出异常.

这也是为了避免AsyncTask并行执行,避免同一个任务同时被执行而造成混乱,因为并行模式时各线程间是无序执行的。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值