Android AsyncTask源码简要分析
来源:互联网 发布:福利软件 编辑:程序博客网 时间:2024/05/19 09:13
AsyncTask
初学 Android 的线程使用时接触最多的就是 AsyncTask 了,直到现在都还没有仔细查看过这个类的源码和实现,有愧于心啊。不说多的,本篇主要根据 AsyncTask 的类结构来进行简要说明,大致的介绍官方都写在文档或者注释中了,我们需要仔细研读。
AysncTask 只适用于最多几秒的操作场景,如果有更高的需求官方强烈推荐使用 Executor / ThreadPoolExecutor / FutureTask 等。AsyncTask分为几个部分:
postResult
当 doInBackground() 方法执行完毕后会将异步执行得到的结果回调给 postResult(),postResult() 将数据抛给InternalHandler。
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result;}
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; } }}
我们看到 InternalHandler 的两种 case,前者调用了 finish() 传递数据到 onPostExecute() 方法,后者调用 onProgressUpdate() 方法更新进度条。AsyncTask 能够进行 UI 操作实际就是通过 InternalHandler 进行的
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED;}
在AsyncTask中内部获取 Handler 是由单例模式生成的实例:
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
AsyncTaskResult
充当 Entity 的作用。调用 onPostExecute 的时候是通过 handler 先将数据放在 AsyncTaskResult 对象中再传递到InternalHandler 中进行UI操作
@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
ThreadPoolExecutor
AsyncTask 实际就是通过线程池实现的异步队列,可以不停的往队列中添加任务,边取边放以达到多线程的操作。
/** * An {@link Executor} that can be used to execute tasks in parallel. */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;}
Status
枚举类,表示当前Task的状态
/** * Indicates the current status of the task. Each status will be set only once * during the lifetime of a task. */ public enum Status { /** * Indicates that the task has not been executed yet. */ PENDING, /** * Indicates that the task is running. */ RUNNING, /** * Indicates that {@link AsyncTask#onPostExecute} has finished. */ FINISHED, }
Binder
AsyncTask 构造函数开始就使用了Binder的方法:
/** * Flush any Binder commands pending in the current thread to the kernel * driver. This can be * useful to call before performing an operation that may block for a long * time, to ensure that any pending object references have been released * in order to prevent the process from holding on to objects longer than * it needs to. */ public static final native void flushPendingCommands();
WorkerRunnable
在构造函数初始化时有两个部分,一个是mWorker,另一个是mFuture。前者实现了Callable接口,目的是为的是接收外部传来的参数,通过实现Callable,以 call() 方法将用户参数传入 doInBackground() 得到 Result。
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } };
Future
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 occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } }};
executeOnExecutor
@MainThreadpublic 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;}
execute
想要启动AsyncTask,就必须执行此方法,方法中使用了sDefaultExecutor
/** * Convenience version of {@link #execute(Object...)} for use with * a simple Runnable object. See {@link #execute(Object[])} for more * information on the order of execution. * * @see #execute(Object[]) * @see #executeOnExecutor(java.util.concurrent.Executor, Object[]) */@MainThreadpublic static void execute(Runnable runnable) { sDefaultExecutor.execute(runnable);}
SerialExecutor
关键部分,AsyncTask 中的队列就是这个类的 ArrayDeque 实现的,最后 execute 执行的是这个类中的方法。
/** * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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); } } }
AsyncTask 的使用注意事项
在官方的 性能优化典范(五) (中文戳这儿 —> ) Android性能优化典范 - 第5季中已经写得很明确了,以下引用自胡凯大神的译文:
4)Good AsyncTask Hunting
AsyncTask是一个让人既爱又恨的组件,它提供了一种简便的异步处理机制,但是它又同时引入了一些令人厌恶的麻烦。一旦对AsyncTask使用不当,很可能对程序的性能带来负面影响,同时还可能导致内存泄露。
举个例子,常遇到的一个典型的使用场景:用户切换到某个界面,触发了界面上的图片的加载操作,因为图片的加载相对来说耗时比较长,我们需要在子线程中处理图片的加载,当图片在子线程中处理完成之后,再把处理好的图片返回给主线程,交给UI更新到画面上。
AsyncTask的出现就是为了快速的实现上面的使用场景,AsyncTask把在主线程里面的准备工作放到onPreExecute()
方法里面进行执行,doInBackground()
方法执行在工作线程中,用来处理那些繁重的任务,一旦任务执行完毕,就会调用onPostExecute()
方法返回到主线程。
使用AsyncTask需要注意的问题有哪些呢?请关注以下几点:
- 首先,默认情况下,所有的AsyncTask任务都是被线性调度执行的,他们处在同一个任务队列当中,按顺序逐个执行。假设你按照顺序启动20个AsyncTask,一旦其中的某个AsyncTask执行时间过长,队列中的其他剩余AsyncTask都处于阻塞状态,必须等到该任务执行完毕之后才能够有机会执行下一个任务。情况如下图所示:
为了解决上面提到的线性队列等待的问题,我们可以使用AsyncTask.executeOnExecutor()
强制指定AsyncTask使用线程池并发调度任务。
- 其次,如何才能够真正的取消一个AsyncTask的执行呢?我们知道AsyncTaks有提供
cancel()
的方法,但是这个方法实际上做了什么事情呢?线程本身并不具备中止正在执行的代码的能力,为了能够让一个线程更早的被销毁,我们需要在doInBackground()
的代码中不断的添加程序是否被中止的判断逻辑,如下图所示:
一旦任务被成功中止,AsyncTask就不会继续调用onPostExecute()
,而是通过调用onCancelled()
的回调方法反馈任务执行取消的结果。我们可以根据任务回调到哪个方法(是onPostExecute还是onCancelled)来决定是对UI进行正常的更新还是把对应的任务所占用的内存进行销毁等。
- 最后,使用AsyncTask很容易导致内存泄漏,一旦把AsyncTask写成Activity的内部类的形式就很容易因为AsyncTask生命周期的不确定而导致Activity发生泄漏。
综上所述,AsyncTask虽然提供了一种简单便捷的异步机制,但是我们还是很有必要特别关注到他的缺点,避免出现因为使用错误而导致的严重系统性能问题。
- Android AsyncTask源码简要分析
- Android AsyncTask简要分析
- Android AsyncTask源码分析
- Android源码分析--AsyncTask
- 源码分析Android AsyncTask
- Android AsyncTask源码分析
- Android-AsyncTask源码分析
- Android AsyncTask 源码分析
- android-----AsyncTask源码分析
- Android AsyncTask源码分析
- Android AsyncTask源码分析
- Android源码分析-AsyncTask
- 【Android】 AsyncTask 源码分析
- Android AsyncTask源码分析
- android源码分析-AsyncTask
- Android源码路径简要分析
- Android的AsyncTask源码分析
- Android AsyncTask源码简单分析
- c#图解
- 扩频通信
- LeetCode 137. Single Number II
- JAVA面试重点总结
- 一个合法的表达式由()包围,()可以嵌套和连接,如(())()也是合法表达式;现在有 6 对(),它们可以组成的合法表达式的个数为_132___
- Android AsyncTask源码简要分析
- 设备树学习之(九)SPI设备注册过程
- php5.4+ CI框架中无法写日志
- git搭建局域网服务器
- 如何用github+hexo搭建个人博客
- Redis String、List、Set、Hash、ZSet常用命令
- HDU3555 Bomb 数位DP经典题
- vue 动画过渡
- 算法提高 输入输出格式练习