内容简介:Android AsyncTask
- Android Studio 2.3
-
API 21
-
简介和用法
- RTFSC
AsyncTask 简介
AsyncTask有助于使用UI线程。这个类能让你不主动使用多线程或Handler,在UI线程进行后台操作并发布结果。
AsyncTask是一个在不用多线程和Handler的情况下的帮助类。AsyncTask适用于短时间的操作(最多几秒)。
如需长时间的线程操作,建议使用多线程包 java.util.concurrent
中的API,比如 Executor
, ThreadPoolExecutor
和 FutureTask
AsyncTask任务的构成:
-
3种泛型:
Params
,Progress
和Result
-
4个步骤:
onPreExecute
,doInBackground
,onProgressUpdate
和onPostExecute
用法简介
虚构一个计算任务
/** * 虚拟的计算任务 */ private class CalculationTaskextends AsyncTask<Float,Integer,Float>{ protectedFloatdoInBackground(Float... inputs){ Log.d(TAG, "doInBackground thread ID = " + Thread.currentThread().getId()); long step = 0; float result = 0; for (float f : inputs) { // 假设这里有一些耗时的操作 result += f; } while (step < 5) { result += step; step++; publishProgress((int) step); } return result; } protected void onProgressUpdate(Integer... progress){ Log.d(TAG, "onProgressUpdate thread ID = " + Thread.currentThread().getId()); Log.d(TAG, "onProgressUpdate: " + progress[0]); } protected void onPostExecute(Float result){ Log.d(TAG, "onPostExecute thread ID = " + Thread.currentThread().getId()); Log.d(TAG, "任务执行完毕"); } } // 执行任务 new CalculationTask().execute(1.2f, 2.3f, 6.3f); /* logcat Main thread ID = 1 doInBackground thread ID = 8089 onProgressUpdate thread ID = 1 onProgressUpdate: 1 ... onProgressUpdate thread ID = 1 onProgressUpdate: 5 onPostExecute thread ID = 1 任务执行完毕 */
AsyncTask 使用的的泛型
AsyncTask使用的3种泛型
- Params 送去执行的类型
- Progress 后台计算的进度类型
- Result 后台计算的结果
不用的泛型可以用 Void
表示。例如
private class MyTaskextends AsyncTask<Void,Void,Void>{ ... }
异步任务的4个步骤
异步任务执行时经过4个步骤
-
onPreExecute()
UI线程在任务开始前调用这个方法。此方法常用来设置任务,比如在屏幕上显示一个进度条。 -
doInBackground(Params...)
onPreExecute()
执行完毕后立即在后台线程中执行。这一步用来执行耗时的后台计算。
这个方法接受异步任务的参数,返回最后的任务结果。这一步可以调用publishProgress(Progress...)
通知出去一个或多个进度。这些进度值会被onProgressUpdate(Progress...)
在UI线程收到。 -
onProgressUpdate(Progress...)
调用publishProgress(Progress...)
后会在UI线程中执行。用来显示执行中任务的UI。 -
onPostExecute(Result)
后台任务执行完毕时被调用。最终结果会被传入这个方法。
取消任务
调用 cancel(boolean)
可随时取消任务。取消任务后 isCancelled()
会返回true。
调用这个方法后,后台任务 doInBackground(Object[])
执行完毕后会调用 onCancelled(Object)
而不再是 onPostExecute(Object)
。
为保证任务能被及时地取消,在 doInBackground(Object[])
中应该经常检查 isCancelled()
返回值
线程规则 Threading rules
一些线程规则
- 异步任务必须从UI线程启动
- 必须在UI线程实例化AsyncTask类
-
必须在UI线程调用
execute(Params...)
-
不要手动调用
onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
-
同一个异步任务实例只能被执行一次。重复执行同一个异步任务实例会抛出异常(
IllegalStateException
)。
源码简析
AsyncTask是如何调用后台线程完成任务的?线程是如何调度的?
AsyncTask使用 Executor
,利用 WorkerRunnable
和 FutureTask
来执行后台任务
private final WorkerRunnable<Params, Result> mWorker; // 实现了 Callable private final FutureTask<Result> mFuture; private static abstract class WorkerRunnable<Params,Result>implements Callable<Result>{ Params[] mParams; }
使用 Handler
来进行线程调度。内部定义了一个类 InternalHandler
。
从 execute(Params... params)
方法切入
先看方法 execute(Params... params)
,使用默认执行器,并传入参数
调用 xecuteOnExecutor(Executor exec, Params... params)
@MainThread // 指定在主线程执行 public finalAsyncTask<Params, Progress, Result>execute(Params... params){ return executeOnExecutor(sDefaultExecutor, params); }
先判断当前状态,如果状态不是 Status.PENDING
,则抛出异常。
否则进入 Status.RUNNING
状态,执行 onPreExecute()
,再由执行器启动任务。
@MainThread public finalAsyncTask<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; }
mWorker
带着传进来的参数, mFuture
实例化时已经将 mWorker
注入。参看构造函数
public AsyncTask(){ mWorker = new WorkerRunnable<Params, Result>() { publicResultcall()throwsException{ mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 在后台线程进行自定义的操作 这里面可以调用publishProgress方法 Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); // 发送最终结果 } }; mFuture = new FutureTask<Result>(mWorker) { // 依赖 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); } } }; }
publishProgress
方法通过主线程的Handler向外通知进度
@WorkerThread protected final void publishProgress(Progress... values){ if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
后台任务执行完毕, postResult
发送最终结果
privateResultpostResult(Result result){ @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); // 会走到finish方法 return result; } private void finish(Result result){ if (isCancelled()) { onCancelled(result); // 如果任务已经被取消了 } else { onPostExecute(result); // 通知任务执行完毕 } mStatus = Status.FINISHED; }
关于默认执行器 sDefaultExecutor
和线程池
源码中构建了一个线程池和一个自定义的执行器 SerialExecutor
。靠它们来执行后台任务。
参考源代码
public abstract class AsyncTask<Params,Progress,Result>{ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); // 核心线程至少2个,最多4个 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; public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); publicThreadnewThread(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; } // 默认执行器的类 private static class SerialExecutorimplements Executor{ final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(finalRunnable 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); } } } }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Android AsyncTask
- Android AsyncTask 源码分析
- Android源码系列(15) -- AsyncTask
- Android中的AsyncTask的工作原理
- android – RxJava2优于AsyncTask
- Android多线程-AsyncTask工作流程(源码)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
电脑报(上下册)
电脑报社 / 西南师范大学出版社 / 2006-12-01 / 45.00元
全套上、下两册,浓缩2006年电脑报精华文章。附录包含70余篇简明IT应用指南,覆盖软件、硬盘、数码、网络四大领域。配赠权威实用的2006-2007中国计算机年鉴DVD光盘,近1.4GB海量信息与资源超值奉献。8大正版超值软件,涵盖系统维护、系统安全、办公应用、多媒体娱乐等四大领域。微软、腾讯、友立等知名厂商,新年献礼。提供2006-2007全系列硬件、数码产品资讯,兼具知识性与资料性。官方网站全......一起来看看 《电脑报(上下册)》 这本书的介绍吧!