Android源码探究之AsyncTask 源码解析
2016-07-24 14:44
471 查看
AsyncTask源码使用 Api23版本,后面介绍和以前版本改动不同之处。
先看使用:
使用:
下面进入到源码探究:
从以上可以看出AsyncTask内部是使用线程池,并构建一个队列容量为128,并使用了static修饰,也就是说所有AsyncTask对象都共用一个线程池。
接着看构造方法:
在构造方法中创建了两个对象mWorker 和mFuture ,其中mFuture 需要mWorker作为参数,由于doInBackground方法的执行需要调用call方法的,所以mFuture 对象的FutureTask类内部肯定有调用call方法的操作。
接着看execute方法,因为肯定要调用execute才能执行:
这里有两个参数不一样的execute方法,第一个是我用比较多的,我们先看第一个内部实现:
从上面先进行条件判断抛异常可以看出如果任务正在执行或已经执行完了都会抛异常也就是一个AsyncTask对象只能执行execute(Params… params)一次,而不能这样使用:
注意:execute(Runnable runnable)除外。
接着看executeOnExecutor()方法的下半部分:
从这里可以看出首先会执行onPreExecute()方法也就是我们可以重写的方法,接着会进行把参数赋给mWorker然后执行exec.execute(mFuture);并并需要mFuture参数,由于mWorker已经是mFuture对象的成员变量了,可以查看AsyncTask的构造函数,所以mFuture也可以获取params信息。
此方法最后执行exec.execute(mFuture);那就要看exec对象的execute()方法了,从下面方法:
可以看出exec其实是sDefaultExecutor,那我们查找这个对象的类结构了,这个sDefaultExecutor其实是SerialExecutor 的对象,那就看下该类的实现了。
从exec.execute(mFuture);方法可以查出,最终会调用SerialExecutor类的execute()方法,从内部可以看出调用两个r.run()方法,也就是会调用mFuture的run方法,因为它是通过参数传递过来的,这是其一,其二也可以看出为啥一个任务执行完才到下一个,因为利用了try/finally方式,把任务放到try块中,等执行完后才会到finally块,不断的从双端队列中取任务进行执行。
从这个方法中可以看出,所提交的任务最终会通过线程池内部执行run方法,想了解线程池内部是如何进行执行的可以查看:Java线程池总结之从使用探究源码实现
接着我们再看mFuture内部的run方法是怎样的:
从上面可以看出,首先获取callable对象,然后进行调用,该对象是创建AsyncTask时就已经创建并向mFuture传入,在回顾下:
该mWorker 其实是实现了Callable接口,所以可以进行传入,回到mFuture的run方法,接着会调用call方法:
result = c.call();调用call方法其实也就是调用mWorker的call方法,至此终于执行doInBackground(mParams);方法并把参数传进去,也是我们继承AsyncTask需要重写的doInBackground方法,在mWorker的call方法中执行完doInBackground方法后的结果将会通过handler返回给主线程:
再看postResult(result)方法:
这里通过message.sendToTarget();发消息的方式进行跨线程传递,接着我们再看Handler子类:
接着再看finish(result.mData[0])方法:
这里先判断该任务有没有被取消,如果没有最后把结果返回给onPostExecute()方法,至此就完成onPreExecute()–>doInBackground–>onPostExecute的过程。
接下来看在doInBackground()方法内部调用publishProgress()所传的值是如何传递到onProgressUpdate()方法的:
从上面可以看出也是通过handler进行跨线程传输的,这里使用了MESSAGE_POST_PROGRESS标记,那我们就看看handleMessage()方法:
从上面就可以看出最终调用了onProgressUpdate(result.mData);方法
我们再了解下第二个方法execute(Runnable runnable),它所需参数为runnable,我们在看内部实现:
它通过sDefaultExecutor对象调用execute方法,sDefaultExecutor其实是SerialExecutor类的对象,内部也是通过把任务放到线程池中执行:
由于public static void execute(Runnable runnable);是个静态方法,使用方式如下:
那么也就不经过onPreExecute()–>doInBackground–>onPostExecute的过程,但需要注意的是run方法是在子线程执行,最终执行完也没有进行跨线程操作。
下面了解下Api23的AsyncTask类的一些和Api23以前版本不一样的地方,其中是public final boolean cancel(boolean mayInterruptIfRunning)方法,在以前的版本中,该方法只是起了标记作用,并没有为我们添加了取消执行任务操作,而现在版本已经为我们做了这步操作,看下方法实现:
该方法内部会进行mFuture.cancel()操作,接着看下mFuture内部的cancel方法:
如果任务没开始执行也就是在等待状态,就可以被取消了。从finish方法也可以看出:
从上面方法可以看出,就是任务不能被阻止,执行完了,最终结果也不能传递到onPostExecute(result);方法。
这就是api23版本AsyncTask比较大的改动之一,这样我们无需再自己做判断,内部已经帮我们实现,想取消调用cancel() 方法即可,最终结果不会调用onPostExecute() 方法进行回传。
先看使用:
/** * 下面四个方法中除了doInBackground方法在子线程,其他方法都在主线程执行 * String 表示传进来的参数, * Void 表示子线程执行过程中对主线程进行反馈所传的数据类型 * Integer 子线程执行的结果 */ private class MyAsyncTask extends AsyncTask<String,Void,Integer>{ @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Integer doInBackground(String... params) { /** * 子线程做些耗时操作 如需在主线程中进行反馈 * 则调用 publishProgress(..);方法,数据最终会传到onProgressUpdate(Void... values)方法 */ return null; } @Override protected void onPostExecute(Integer integer) { super.onPostExecute(integer); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } }
使用:
new MyAsyncTask().execute(); . . .
下面进入到源码探究:
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; //线程工厂类 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); /** * An {@link Executor} that can be used to execute tasks in parallel. */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
从以上可以看出AsyncTask内部是使用线程池,并构建一个队列容量为128,并使用了static修饰,也就是说所有AsyncTask对象都共用一个线程池。
接着看构造方法:
public AsyncTask() { 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); } }; 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); } } }; }
在构造方法中创建了两个对象mWorker 和mFuture ,其中mFuture 需要mWorker作为参数,由于doInBackground方法的执行需要调用call方法的,所以mFuture 对象的FutureTask类内部肯定有调用call方法的操作。
接着看execute方法,因为肯定要调用execute才能执行:
execute(Params... params); execute(Runnable runnable);
这里有两个参数不一样的execute方法,第一个是我用比较多的,我们先看第一个内部实现:
@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; }
从上面先进行条件判断抛异常可以看出如果任务正在执行或已经执行完了都会抛异常也就是一个AsyncTask对象只能执行execute(Params… params)一次,而不能这样使用:
MyAsyncTask task = new MyAsyncTask(); task.execute(""); task.execute(""); ...
注意:execute(Runnable runnable)除外。
接着看executeOnExecutor()方法的下半部分:
mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture);
从这里可以看出首先会执行onPreExecute()方法也就是我们可以重写的方法,接着会进行把参数赋给mWorker然后执行exec.execute(mFuture);并并需要mFuture参数,由于mWorker已经是mFuture对象的成员变量了,可以查看AsyncTask的构造函数,所以mFuture也可以获取params信息。
此方法最后执行exec.execute(mFuture);那就要看exec对象的execute()方法了,从下面方法:
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
可以看出exec其实是sDefaultExecutor,那我们查找这个对象的类结构了,这个sDefaultExecutor其实是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); } } }
从exec.execute(mFuture);方法可以查出,最终会调用SerialExecutor类的execute()方法,从内部可以看出调用两个r.run()方法,也就是会调用mFuture的run方法,因为它是通过参数传递过来的,这是其一,其二也可以看出为啥一个任务执行完才到下一个,因为利用了try/finally方式,把任务放到try块中,等执行完后才会到finally块,不断的从双端队列中取任务进行执行。
protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }
从这个方法中可以看出,所提交的任务最终会通过线程池内部执行run方法,想了解线程池内部是如何进行执行的可以查看:Java线程池总结之从使用探究源码实现
接着我们再看mFuture内部的run方法是怎样的:
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { Callable<V> c = callable;//《1》获取传进来的callable if (c != null && state == NEW) { V result; boolean ran; try { result = c.call();//《2》进行执行 ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
从上面可以看出,首先获取callable对象,然后进行调用,该对象是创建AsyncTask时就已经创建并向mFuture传入,在回顾下:
public AsyncTask() { 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); } }; 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); } } }; }
该mWorker 其实是实现了Callable接口,所以可以进行传入,回到mFuture的run方法,接着会调用call方法:
try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result);
result = c.call();调用call方法其实也就是调用mWorker的call方法,至此终于执行doInBackground(mParams);方法并把参数传进去,也是我们继承AsyncTask需要重写的doInBackground方法,在mWorker的call方法中执行完doInBackground方法后的结果将会通过handler返回给主线程:
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); }
再看postResult(result)方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
这里通过message.sendToTarget();发消息的方式进行跨线程传递,接着我们再看Handler子类:
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; } } }
接着再看finish(result.mData[0])方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
这里先判断该任务有没有被取消,如果没有最后把结果返回给onPostExecute()方法,至此就完成onPreExecute()–>doInBackground–>onPostExecute的过程。
接下来看在doInBackground()方法内部调用publishProgress()所传的值是如何传递到onProgressUpdate()方法的:
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
从上面可以看出也是通过handler进行跨线程传输的,这里使用了MESSAGE_POST_PROGRESS标记,那我们就看看handleMessage()方法:
@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; } }
从上面就可以看出最终调用了onProgressUpdate(result.mData);方法
我们再了解下第二个方法execute(Runnable runnable),它所需参数为runnable,我们在看内部实现:
@MainThread public static void execute(Runnable runnable) { sDefaultExecutor.execute(runnable); }
它通过sDefaultExecutor对象调用execute方法,sDefaultExecutor其实是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); } } }
由于public static void execute(Runnable runnable);是个静态方法,使用方式如下:
AsyncTask.execute(new Runnable() { @Override public void run() { } });
那么也就不经过onPreExecute()–>doInBackground–>onPostExecute的过程,但需要注意的是run方法是在子线程执行,最终执行完也没有进行跨线程操作。
下面了解下Api23的AsyncTask类的一些和Api23以前版本不一样的地方,其中是public final boolean cancel(boolean mayInterruptIfRunning)方法,在以前的版本中,该方法只是起了标记作用,并没有为我们添加了取消执行任务操作,而现在版本已经为我们做了这步操作,看下方法实现:
public final boolean cancel(boolean mayInterruptIfRunning) { mCancelled.set(true); return mFuture.cancel(mayInterruptIfRunning); }
该方法内部会进行mFuture.cancel()操作,接着看下mFuture内部的cancel方法:
public boolean cancel(boolean mayInterruptIfRunning) { if (!(state == NEW && U.compareAndSwapInt(this, STATE, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; try { // in case call to interrupt throws exception if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) t.interrupt();//从这里可以看出会进行一个打断操作 } finally { // final state U.putOrderedInt(this, STATE, INTERRUPTED); } } } finally { finishCompletion(); } return true; }
如果任务没开始执行也就是在等待状态,就可以被取消了。从finish方法也可以看出:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
@MainThread
protected void onCancelled() {
}
从上面方法可以看出,就是任务不能被阻止,执行完了,最终结果也不能传递到onPostExecute(result);方法。
这就是api23版本AsyncTask比较大的改动之一,这样我们无需再自己做判断,内部已经帮我们实现,想取消调用cancel() 方法即可,最终结果不会调用onPostExecute() 方法进行回传。
相关文章推荐
- 使用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