Android——AsyncTask

来源:互联网 发布:淘宝上质量好的外贸店 编辑:程序博客网 时间:2024/06/05 10:56

  我们都会有这样的需求,比如从网络上进行耗时的操作然后拿到数据,然后把数据更新到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);        }    }
还记得在  publicFutureTask(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
原创粉丝点击