查看源码 AsyncTask
只是对 Thread
和 Handler
的一个封装,其中线程是使用线程池技术。
基本概念 1 2 3 4 5 6 7 8 9 10 11 public abstract class AsyncTask <Params , Progress , Result > { public AsyncTask () {...} protected void onPreExecute () {...} protected abstract Result doInBackground (Params... params) ; protected void onProgressUpdate (Progress... values) {...} protected void onPostExecute (Result result) {...} public final AsyncTask<Params, Progress, Result> execute (Params... params) {...} public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params) {...} public static void execute (Runnable runnable) {...} ... }
3 个泛型参数 AsyncTask <Params, Progress, Result>
Params
指定的是我们传递给异步任务执行时的参数的类型。注意:这里是可变长参数 ,如果只传递了一个参数,使用时为 params[0]
。
Progress
指定的是我们的异步任务在执行的时候将执行的进度返回给 UI
线程的参数的类型。注意:这里也是可变长参数 ,如果只传递了一个参数,使用时为 progress[0]
。
Result
指定的是异步任务执行完后返回给 UI
线程的结果的类型。
我们在定义一个类继承 AsyncTask
类的时候,必须指定好这三个泛型的类型,如果都不指定的,则将其写成 Void
。
4 个执行步骤
onPreExecute()
UI Thread
当中执行,这个方法是在执行异步任务之前的时候执行,我们可以在异步任务执行前做 UI
提示。
doInBackground(Params... params)
这个方法就是来处理异步任务的方法,执行耗时操作。这个方法也是必须要实现的抽象方法。
onProgressUpdate(Progess... values)
UI Thread
当中执行,用来更新进度条等。
onPostExecute(Result... result)
UI Thread
当中执行,当异步任务执行完之后,将 doInBackground
结果返回给这个方法来更新 UI
。
2 种执行方式 “执行”必须在主线程 中调用,而后台线程的执行方式可以为串行或者并行执行。
串行:execute(Params... params)/execute(Runnable runnable)
并行:executeOnExecutor(Executor exec, Params... params)
注意 :各 SDK
版本 execute
默认执行方式不统一,1.5 中顺序执行,1.6 到 2.3 中并行执行,3.0 以后又改回串行执行,并添加并行执行接口 executeOnExecutor
。
注意事项
必须在 UI
线程中加载和创建,以及调用 execute
不能做特别耗时的操作,建议只几秒内的异步任务
一个 AsyncTask
对象只能被执行一次,即只能调用一次 execute
,否则会抛出异常报错:Caused by: java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
不能在程序中主动调用 4 个步骤
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 protected void function () { ... mClassifierAsyncTask = new ClassifierAsyncTask(); mClassifierAsyncTask.execute(bitmap); } private ClassifierAsyncTask mClassifierAsyncTask;private class ClassifierAsyncTask extends AsyncTask <Bitmap , Void , String > { @Override protected void onPreExecute () { super .onPreExecute(); mTvResult.setText(getString(R.string.classifying)); } @Override protected String doInBackground (Bitmap... bitmaps) { if (mMyTfClassifier == null ) { mMyTfClassifier = new MyTfClassifier(MainActivity.this ); } String result = mMyTfClassifier.recognizeImage(bitmaps[0 ]); return result; } @Override protected void onPostExecute (String result) { super .onPostExecute(result); mTvResult.setText(result); } }
源码解析 线程池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();private static final int CORE_POOL_SIZE = Math.max(2 , Math.min(CPU_COUNT - 1 , 4 ));private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1 ;private static final int KEEP_ALIVE_SECONDS = 30 ;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()); } }; private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128 ); public static final Executor THREAD_POOL_EXECUTOR;static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true ); THREAD_POOL_EXECUTOR = threadPoolExecutor; }
参数及返回结果封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private static abstract class WorkerRunnable <Params , Result > implements Callable <Result > { Params[] mParams; } private final WorkerRunnable<Params, Result> mWorker;private final FutureTask<Result> mFuture;public AsyncTask () { mWorker = new WorkerRunnable<Params, Result>() { public Result call () throws Exception { mTaskInvoked.set(true ); Result result = null ; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true ); throw tr; } finally { postResult(result); } return result; } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done () { ... postResultIfNotInvoked(get()); ... } }; }
在构造方法中,传进来的参数 Params
被包装成到 mWorker
中,它是一个 Callable
。同时在 mWorker
中定义了返回结果类型 Result
,并在 call
中调用了回调方法 doInBackground
,执行具体的后台任务。最后 mWorker
包装到 FutureTask
中,当执行完毕后,通过 get()
获取执行的结果,并通知 UI
去更新。
任务执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @MainThread public final AsyncTask<Params, Progress, Result> execute (Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params) { ... onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this ; }
不管是串行还是并行,最终都调用了 executeOnExecutor
,这里才真正的把参数传递进来,参数赋值给 mWorker
,根据构造方法中参数封装的分析,mFuture
携带了参数和返回值类型,此时只需要调用执行器执行即可 exec.execute(mFuture);
。
串行执行 示例:mClassifierAsyncTask.execute(bitmap);
,串行执行源码分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @MainThread public final AsyncTask<Params, Progress, Result> execute (Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread public static void execute (Runnable runnable) { sDefaultExecutor.execute(runnable); } public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;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); } } }
并行执行 示例:mClassifierAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, bitmaps);
,并行执行源码见任务执行 。
1 2 3 4 public static final Executor THREAD_POOL_EXECUTOR;
查看默认线程池定义,THREAD_POOL_EXECUTOR
是 static final
类型的,可以作为并行 Executor
来使用,或者用户也可以自定义。
存在的问题 Activity
屏幕旋转或销毁时,如果 AsyncTask
没有执行完毕就会存在内存泄露。特别是屏幕旋转时 AsyncTask
没有执行完毕,会导致屏幕异常。