Android——AsyncTask

  我们都会有这样的需求,比如从网络上进行耗时的操作然后拿到数据,然后把数据更新到UI上,我们一般的做法就是在子线程中进行耗时的操作,然后在主线程中进行UI的更新,如果要是在UI线程中进行耗时的操作可能会导致ANR的发生。

    Android中已经为我们封装好了一个类--AsyncTask,它内部实现主要就是Handler+Thread,接下来让我们一起看看源码来了解一下用法。

在查看源码时,我们先从类的注解看起。

* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
 * and does not constitute a generic threading framework. AsyncTasks should ideally be
 * used for short operations (a few seconds at the most.) If you need to keep threads
 * running for long periods of time, it is highly recommended you use the various APIs
 * provided by the <code>java.util.concurrent</code> package such as {@link Executor},
 * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
这段源码告诉我们,AsyncTask的内部实现是Handler+Thread,它只适应于短时间(几秒钟)的耗时操作,而不适应于长时间的耗时操作,若需要长时间的操作,可以用Executor、ThreadPoolExecutore、FutureTask。

<p>An asynchronous task is defined by a computation that runs on a background thread and
 * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
 * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
 * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
 * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
这段源码讲,它的数据获取在子线程中,最终结果的处理会在UI线程中,它是一个抽象的泛型类

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

里面有三个泛型参数:

<li><code>Params</code>, the type of the parameters sent to the task upon
 *     execution.</li>
 *     <li><code>Progress</code>, the type of the progress units published during
 *     the background computation.</li>
 *     <li><code>Result</code>, the type of the result of the background
 *     computation.</li>

Params:参数的类型

Progress:当前进度的类型

Result:返回结果的类型

注解中提到重要的4个核心方法:

<li>{@link #onPreExecute()}, invoked on the UI thread before the task
 *     is executed. This step is normally used to setup the task, for instance by
 *     showing a progress bar in the user interface.</li>
 *     <li>{@link #doInBackground}, invoked on the background thread
 *     immediately after {@link #onPreExecute()} finishes executing. This step is used
 *     to perform background computation that can take a long time. The parameters
 *     of the asynchronous task are passed to this step. The result of the computation must
 *     be returned by this step and will be passed back to the last step. This step
 *     can also use {@link #publishProgress} to publish one or more units
 *     of progress. These values are published on the UI thread, in the
 *     {@link #onProgressUpdate} step.</li>
 *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a
 *     call to {@link #publishProgress}. The timing of the execution is
 *     undefined. This method is used to display any form of progress in the user
 *     interface while the background computation is still executing. For instance,
 *     it can be used to animate a progress bar or show logs in a text field.</li>
 *     <li>{@link #onPostExecute}, invoked on the UI thread after the background
 *     computation finishes. The result of the background computation is passed to
 *     this step as a parameter.</li>
onPreExecute:在主线程中执行,在异步任务执行之前被调用,主要是用于进行一些初始化的工作

doInBackground:在子线程中执行,在onPreExecute之后执行,主要用于做一些耗时的操作,返回的结果最终会交给onPostExecute,也可以调用publishProgress来更新进度,然后回调onProgressUpdate

onProgressUpdate:在主线程中执行,主要是对publishProgress中返回的进度进行处理

onPostExecute:在主线程中执行,对doInBackground返回的结果进行处理

接下来看一下官方给出的一个例子:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 *     protected Long doInBackground(URL... urls) {
 *         int count = urls.length;
 *         long totalSize = 0;
 *         for (int i = 0; i < count; i++) {
 *             totalSize += Downloader.downloadFile(urls[i]);
 *             publishProgress((int) ((i / (float) count) * 100));
 *             // Escape early if cancel() is called
 *             if (isCancelled()) break;
 *         }
 *         return totalSize;
 *     }
 *
 *     protected void onProgressUpdate(Integer... progress) {
 *         setProgressPercent(progress[0]);
 *     }
 *
 *     protected void onPostExecute(Long result) {
 *         showDialog("Downloaded " + result + " bytes");
 *     }
 * }
使用方法:

在线程中加入下面代码:

new DownloadFilesTask().execute(url1, url2, url3);


接下来我们就开始进入分析AsyncTask工作的逻辑处理:

首先看AsyncTask的构造方法:

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

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        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 occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

FutureTask实现了Future、Runnbale接口,它的get()方法是支持阻塞的,而且它的构造函数中支持传进CallBack类型的参数:

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
所以带有返回值,介于这两点,futureTask可以被用来作为 预加载数据处理
在这里,Future是对mWoker进行封装,当做Runnable来处理

然后看execute():

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
调用了executeOnExecutor(),里面sDefaultExecutor参数是SerialExecuotr的一个实例:

 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);
            }
        }
    }
可以看出,SerialExecutor实现啦Executor接口,在execute方法中,它首先把参数Runnable r加入到一个双向队列mTasks中,mActive是判断当前是否有正在运行的AsyncTask,如果没有就会从mTasks中拿出一个Runnable,然后用THREAD_POOL_EXECUTOR线程池来执行该Runnable,当当前的AsyncTask执行完成后会执行下一个Runnable,直到mTask中所有的Runnable执行完成。可以看出,在默认的情况下,AsyncTask是串行执行的。

上面讲到最终执行是通过THREAD_POOL_EXECUTOR来执行任务的:

 public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到THREAD_POOL_EXECUTOR其实就是ThreadPoolExecutor的一个实例,它定义了一个

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;

    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());
        }
    };
核心线程数为:CPU数量+1;

最大线程数为:CPU*2+1;

超时时长为:1s

回到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(),所以要在主线程中对AsyncTask进行初始化,这样onPreExecute()就是在主线程中进行调用。

上面讲到过mFuture中封装了mWorker,所以mFuture中也就有了params。

然后就是调用上面说的SerialExecutor.execute();

 public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
再来看看这个方法,这里的Runnable r 参数其实就是FutureTask,r.run()方法就是FutureTask.run();

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         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);
        }
    }
还记得在   public FutureTask(Callable< V > callable);中 this.callable = callable;

所以这里的 c就是mWorker,然后就调用c.call():

还记得在AsyncTask构造方法中:

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

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };
这里调用了doInBackground(mParam); doInBackground()是AsyncTask中的抽象方法,所以必须被子类所重写,可以看到call()方法是在子线程中被调用的,所以doInBackground是在子线程中进行处理的,所以就可以在方法中进行耗时的操作,记得在doInBackground()中可以调用publishProgress():

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

 private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }
可以看到handler是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;
            }
        }
    }

从构造方法中可以看到,handler中的消息是在主线程中进行处理的

result.mTask返回的是:result所对应的FutureTask

  private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }


可以看到这里接收了两种消息:

1)MESSAGE_POST_RESULT:

调用FutureTask.finish();

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

如果AsyncTask被取消了,就执行onCancelled()

否则就执行onPostExecute()

2)MESSAGE_POST_PROGRESS:
调用onProgressUpdate();

回过头看mWorker中call()方法中的postResult();

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

这里就是发送一个msg.what为MESSAGE_POST_RESULT的消息,然后就是在InternalHandler中进行处理。

到这里,差不多所有的逻辑都走通啦,但是还有一些注意事项和用法:

1)我们在使用时,最好不要自己去调用4大核心方法,否则会有想不到的错误

2)AsyncTask默认情况下是串行执行的,但我们可以主动调用executeOnExecutro()来实现并行执行


好啦,到这里差不多结束啦,谢谢大家的浏览,如果有疑问与不足之处,望请提出,我们共同学习!









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值