AsyncTask源码分析
来源:互联网 发布:mac office软件下载 编辑:程序博客网 时间:2024/06/09 21:01
- AsyncTask简介
- AsyncTask步骤
- 注意事项
- AsyncTask工作原理
- 解决30以上版本不能并行执行的问题
AsyncTask简介
- AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。
- AsyncTask实际上就是封装了Thread和Handler,可以让我们在后台进行计算并且把计算的结果及时更新到UI上,而这些正是Thread+Handler所做的事情,AsyncTask的作用就是简化Thread+Handler
- 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
AsyncTask步骤
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params):
执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
2.onPreExecute():
在execute(Params…params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。在主线程中执行。
3.doInBackground(Params…params):
在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress…values)来更新进度信息。在线程池中执行。
4.onProgressUpdate(Progress…values):
在调用publishProgress(Progress…values)时,此方法被执行,直接将进度信息更新到UI组件上。 在主线程中执行。
5.onPostExecute(Result result):
当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。在主线程中执行。
注意事项
1.异步任务的实例必须在UI线程中创建。
2.AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
3.execute(Params… params)方法必须在UI线程中调用。
4.不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
5.不能在doInBackground(Params… params)中更改UI组件的信息。
6.一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
7.AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
8.在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
AsyncTask工作原理
AsyncTask启动首先会调用execute,先从execute方法开始分析,execute又会调用executeOnExecutor,它们的实现如下:
@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) { 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; }
sDefaultExecutor实现了一个串行的线程池,一个进程中所有的AsyncTask都会在这个线程池中排队。onPreExecute会先执行。然后通过exec.execute(mFuture)执行这个线程池。
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ 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); } } }; }
首先系统会把AsyncTask的mParams参数封装为FutureTask对象,FutureTask是一个并发类。接着这个FutureTask会交给SerialExecutor的execute方法去处理,execute首先会把FutureTask插入任务队列mTasks,详细实现如下:
/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候, *首先你的task会被加入到任务队列,然后排队,一个个执行 */ private static class SerialExecutor implements Executor { //线性双向队列,用来存储所有的AsyncTask任务 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); //当前正在执行的AsyncTask任务 Runnable mActive; public synchronized void execute(final Runnable r) { //将新的AsyncTask任务加入到双向队列中 mTasks.offer(new Runnable() { public void run() { try { //执行AsyncTask任务 r.run(); } finally { //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话 //这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务 scheduleNext(); } } }); //如果当前没有任务在执行,直接进入执行逻辑 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行 if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
SerialExecutor实现了AsyncTask的排队过程。ArrayDeque 类提供了可调整大小的阵列,并实现了Deque接口。从任务队列中取出队列头部的任务,如果有就交给并发线程池HREAD_POOL_EXECUTOR去执行。
THREAD_POOL_EXECUTOR线程池用于真正执行任务。
//获取当前的cpu核心数 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; //ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程 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()); } }; //静态阻塞式队列,用来存放待执行的任务,初始容量:128个 private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); /** * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务 * 但是我们仍然能构造出并行的AsyncTask */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
WorkerRunnable的call()方法最终会在线程池中执行,如下
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)); } };
mTaskInvoked.set(true),表示当前任务已经被调用,然后执行doInBackground方法,接着返回值传递给postResult()方法,如下:
//doInBackground执行完毕,发送消息 private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
postResult会通过sHandler发送一个MESSAGE_POST_RESULT的消息。sHandler实现如下:
//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息 private static class InternalHandler extends Handler { @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; } } }
sHandler收到MESSAGE_POST_RESULT后会调用finish方法,如果被取消任务,就调用onCancelled,否则调用onPostExecute:
//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用 private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
解决3.0以上版本不能并行执行的问题
直接调用executeOnExecutor:
new MyAsyncTask(“AsyncTask#1”).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,”“);
- AsyncTask 源码分析
- AsyncTask源码分析
- Android AsyncTask源码分析
- Android源码分析--AsyncTask
- 源码分析Android AsyncTask
- Android AsyncTask源码分析
- AsyncTask源码分析
- Android-AsyncTask源码分析
- 源码分析--AsyncTask
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- Android AsyncTask 源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- Ajax入门之XMLHttpRequest核心对象的详解
- git常用命令。。百度随便找的
- linux 查看进程
- C语言高效编程与代码优化
- C++拷贝构造函数与浅拷贝,深拷贝
- AsyncTask源码分析
- Subversion 回退历史版本
- java中file的一些用法:文件复制,lis方法和listfiles方法等
- Python从阿里云Oss拉数据写入Hive表并进行相关处理
- 【maven】4、Maven Guide
- iOS路由跳转(三)之JKRouter基础教程1
- 进程学习笔记(未完待续)
- 【ngMiracle】Angular 中的通信方式
- ASP.NET访问sql数据库(课堂学习部分)