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()来实现并行执行
好啦,到这里差不多结束啦,谢谢大家的浏览,如果有疑问与不足之处,望请提出,我们共同学习!
更多相关文章
- Android接口回调机制
- android 5.0 创建多用户 双开多开应用(1)
- Android(安卓)P版本(9.0) 新功能介绍和兼容性处理
- Android(安卓)NDK开发之Jni调用Java对象
- 【Android(安卓)Training - 05】与其他Apps进行交互 [ Lesson 3
- Android设置ProgressBar的前景和背景及其在多线程中的刷新
- android 蓝牙小总结
- 我的Android进阶之旅------>Android基于HTTP协议的多线程断点下
- Android(安卓)HAL层/native C程序打印栈信息方法