AsyncTask源码浅析
2016-06-24 15:34
465 查看
AsyncTask是Android的异步类……恩,大家应该都知道,直接分析吧。开始之前如果对Android的Callable,Future不了解的话可以先看看这篇文章 Java并发编程:Callable、Future和FutureTask
首先看看简单的用法,我自定义了一个TestAsyncTask:
这里简单说一下,这里用到了三个泛型,第一个代表我们执行的任务需要的参数,就是doInBackground里面的参数,第二个泛型是用来更新进度的时候使用的,第三个泛型用来指定返回类型。
用的时候呢
那么就从new开始分析先看一下AsyncTask的构造函数:
首先先创建了一个创建一个WorkerRunnable对象,看源码可以知道这个对象实现了Callable接口,并且把任务封装在了call方法里面,这个方法主要就是执行了doInBackground方法.
然后从、又创建了一个FutureTask对象,看过上面那个文章的应该知道FutureTask既可以当Runnable使用又可以当Future使用。
下面继续看execute(“helloWorld”)方法:
这个方法实际上是调用了executeOnExecutor方法,我们一会再看这个方法,先看一下传入这个方法的两个参数:
先看看sDefaultExecutor的定义:
sDefaultExecutor 就是SerialExecutor,再看看SerialExecutor
可以看出SerialExecutor 中有一个任务队列
params比较简单,就是
可以看出THREAD_POOL_EXECUTOR只是一个常量池。
这样SerialExecutor 的任务就清楚了,将消息放入消息队列,并一个一个地串行地取出并交给THREAD_POOL_EXECUTOR执行
下面接着分析executeOnExecutor,
这段代码首先判断任务是否正在执行或者已经执行完了,如果是,那就抛出异常,否则执行
分析到这里,我们已经可以知道doInBackground就是在THREAD_POOL_EXECUTOR线程池的子线程中执行的。
最后再来看一下postResult(result).方法:
这里可以看到,就是把result放到message中并把getHandler得到的handler作为message的target,把message的what设置成MESSAGE_POST_RESULT表示这个消息代表任务执行的结果。看一下getHandler:
getHandler只是返回了一个InternalHandler
上面的注释写得很明白了,根据消息的不同,使用handler在UI线程中处理结果,或者更新progerss。
看看
看到这里可以总结一下,doInBackground方法是在线程池中的线程中执行,而onPreExecute是在UI线程中执行,而onPostExecute和onProgressUpdate是用过InternalHandler 从而在UI线程执行的。而且一个AsyncTask对象执行结束之后也就没用了,一个AsyncTask对象只能execute一次,否则会报异常,如果还想执行一个任务需要重新创建一个AsyncTask对象,这一点可以从executeOnExecutor的代码看出来
首先看看简单的用法,我自定义了一个TestAsyncTask:
class TestAsyncTask extends AsyncTask<String, Integer, Long> { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); } @Override protected Long doInBackground(String... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } }
这里简单说一下,这里用到了三个泛型,第一个代表我们执行的任务需要的参数,就是doInBackground里面的参数,第二个泛型是用来更新进度的时候使用的,第三个泛型用来指定返回类型。
用的时候呢
new TestAsyncTask().execute("helloWorld");
那么就从new开始分析先看一下AsyncTask的构造函数:
public AsyncTask() { //创建一个WorkerRunnable,这个对象实现了Callable接口 mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked //执行doInBackground Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; //创建一个mFuture 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); } } }; }
首先先创建了一个创建一个WorkerRunnable对象,看源码可以知道这个对象实现了Callable接口,并且把任务封装在了call方法里面,这个方法主要就是执行了doInBackground方法.
然后从、又创建了一个FutureTask对象,看过上面那个文章的应该知道FutureTask既可以当Runnable使用又可以当Future使用。
new FutureTask<Result>(mWorker),这里的Result就是任务执行完之后的返回值的类型,其实FutureTask只是包装了一下mWorker,所以我们要执行的任务就是FutureTask类,主要任务就是执行doInbackground,并把执行结果交给Future。
下面继续看execute(“helloWorld”)方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
这个方法实际上是调用了executeOnExecutor方法,我们一会再看这个方法,先看一下传入这个方法的两个参数:
sDefaultExecutor,和
params
先看看sDefaultExecutor的定义:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
sDefaultExecutor 就是SerialExecutor,再看看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); } } }
可以看出SerialExecutor 中有一个任务队列
mTasks,每次执行
SerialExecutor的
execute方法都会将任务加入这个任务队列,如果当前没有任务在执行,那么久取出一个任务让THREAD_POOL_EXECUTOR执行。THREAD_POOL_EXECUTOR比较简单,
params比较简单,就是
new TestAsyncTask().execute("helloWorld");的时候传入的“hello world”
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看出THREAD_POOL_EXECUTOR只是一个常量池。
这样SerialExecutor 的任务就清楚了,将消息放入消息队列,并一个一个地串行地取出并交给THREAD_POOL_EXECUTOR执行
下面接着分析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() onPreExecute(); //把需要的参数传给mWorker,也就是传给FutherTask即mFuture mWorker.mParams = params; //这里的exec就是我们在execute方法中传给executeOnExecutor的第一个参数也就是sDefaultExecutor exec.execute(mFuture); return this; }
这段代码首先判断任务是否正在执行或者已经执行完了,如果是,那就抛出异常,否则执行
onPreExecute();然后把我们在外面调用
execute("hello world")传入的参数
hello world参数传入mWorker即要执行的任务,然后调用
sDefaultExecutor的
execute方法。之后就像上面介绍的
sDefaultExecutor先把任务加入任务队列然后串行的执行任务,任务的主要内容就是执行
doInBackground并把返回的
Result传入
postResult(result);
分析到这里,我们已经可以知道doInBackground就是在THREAD_POOL_EXECUTOR线程池的子线程中执行的。
最后再来看一下postResult(result).方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") //把result放到message中并发送到getHandler Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
这里可以看到,就是把result放到message中并把getHandler得到的handler作为message的target,把message的what设置成MESSAGE_POST_RESULT表示这个消息代表任务执行的结果。看一下getHandler:
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
getHandler只是返回了一个InternalHandler
//使用的是UI线程的Looper和消息队列 public InternalHandler() { super(Looper.getMainLooper()); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.what) { //what是MESSAGE_POST_RESULT,那么就处理doInbackground返回的结果 case MESSAGE_POST_RESULT: // There is only one result // finish内部会调用我们实现的onPostExecute方法 result.mTask.finish(result.mData[0]); break; //what是MESSAGE_POST_PROGRESS,那么就调用onProgressUpdate来更新progress case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } }
上面的注释写得很明白了,根据消息的不同,使用handler在UI线程中处理结果,或者更新progerss。
看看
finish和的代码
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { //onPostExecute就是在这里执行的 onPostExecute(result); } mStatus = Status.FINISHED; } protected final void publishProgress(Progress... values) { if (!isCancelled()) { //publishProgress把what为MESSAGE_POST_PROGRESS的消息发送给了 // InternalHandler,所以更新了progress getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
看到这里可以总结一下,doInBackground方法是在线程池中的线程中执行,而onPreExecute是在UI线程中执行,而onPostExecute和onProgressUpdate是用过InternalHandler 从而在UI线程执行的。而且一个AsyncTask对象执行结束之后也就没用了,一个AsyncTask对象只能execute一次,否则会报异常,如果还想执行一个任务需要重新创建一个AsyncTask对象,这一点可以从executeOnExecutor的代码看出来
到这里就算大致的分析完了,其实还有许多细节没有提到,感觉自己没有看源码光看别人的文章的话还是很难理解,最好没事的话多翻翻源码,AsyncTask这个类的源码都在一个文件里面也不多。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories