Android AsynTask源码分析和优缺点
2016-03-31 16:07
549 查看
AsynTask是Android SDK中自带的网络请求API,今天来分析下AsynTask的源代码,顺便说一下AsynTask的用法和优缺点。
先来看看AsynTask是怎么用的:
耗时的操作可以在doInBackground做,然后在onPostExecute更新UI即可,在调用doInBackground之前还会先执行onPreExecute做预先处理。AsynTask使用非常简单,但是它也有一些缺点,在说缺点之前我们先看它的源码,首先看看execute方法:
还来看executeOnExecutor方法,在这里把任务赋值为运行状态(Status.RUNNING),这也是为什么一个AsynTask只能执行一次的原因。然后调用了onPreExecute();做一些预先的处理。并且把我们的参数赋值给了mWorker的参数。那么两个变量mWorker(工作线程),mFuture(未来的任务)又是什么呢?这两个变量是在初始化AsynTask的时候在构造方法里实例化的,来看看源代码:
先看mWorker,在实例化mWorker的时候,在回调方法call里调用了doInBackgrou方法然后把result通过postResult发送了出去,来看看是怎么post出去的,看源代码:
AsyncTaskResult里面只有一个AsynTask和一个Data数组。那么就清楚了,在handleMessage的MESSAGE_POST_RESULT分支里result.mTask.finish(result.mData[0]);就很清楚了,其实就是调用的AsynTask的finish方法,在这个方法里调用了onPostExecute,并且把这个任务的状态设置为完成状态,至此整个任务就算完成了,大家可以自己去看看finish里的代码。这个finish方法是在Handler里执行的,也就是在UI线程执行的,所以我们可以在这里做更新UI的操作。
再来看看SerialExecutor,当初始化该类的时候mActive是空的,会执行scheduleNext,其实这里是从线程队列中取出一个任务然后交给线程池去执行。先暂且不管线程池。还来看SerialExecutor的execute方法,当第一个任务执行完之后mActive不为空,所以当再次执行scheduleNext时在finally里调用的,也就是说如果前面的任务没有执行完,下一个任务不会执行,所以当有多个任务的时候,AsynTask是单线程调用的,效率不是很高,虽然有线程池机制。
先来看看AsynTask是怎么用的:
new AsyncTask<Integer, Integer, Integer>() { @Override protected Integer doInBackground(Integer... params) { return null; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onPostExecute(Integer integer) { super.onPostExecute(integer); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } }.execute();AsynTask是泛型的,三个泛型分别是Params, Progress, Result。第一个是请求网络需要的参数,第二个是进度,第三个是请求返回来的结果。
耗时的操作可以在doInBackground做,然后在onPostExecute更新UI即可,在调用doInBackground之前还会先执行onPreExecute做预先处理。AsynTask使用非常简单,但是它也有一些缺点,在说缺点之前我们先看它的源码,首先看看execute方法:
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; }execute调用了executeOnExecutor方法,并且把我们的参数传了过来,另外还传了一个sDefaultExecutor,是Executer类型的,看下面sDefaultExecutor的初始化过程:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; 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实现了Executor接口,这里面实现了一个线程队列mTasks,这个一会再说。
还来看executeOnExecutor方法,在这里把任务赋值为运行状态(Status.RUNNING),这也是为什么一个AsynTask只能执行一次的原因。然后调用了onPreExecute();做一些预先的处理。并且把我们的参数赋值给了mWorker的参数。那么两个变量mWorker(工作线程),mFuture(未来的任务)又是什么呢?这两个变量是在初始化AsynTask的时候在构造方法里实例化的,来看看源代码:
/** * 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 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,在实例化mWorker的时候,在回调方法call里调用了doInBackgrou方法然后把result通过postResult发送了出去,来看看是怎么post出去的,看源代码:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }在postResult方法里得到了一个Handler,看到这就明白了,其实AsynTask也是通过Handler去更新UI的。这个Handler是静态的,并且Looper是主线程里的Looper,看下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; } } }非常简单,就是Handler处理消息。在上面obtainMessage一个Message的时候obj是AsyncTaskResult类型的,实例化的时候并且把result和当前AsynTask传了进去,看下AsyncTaskResult这个类的构造:
@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
AsyncTaskResult里面只有一个AsynTask和一个Data数组。那么就清楚了,在handleMessage的MESSAGE_POST_RESULT分支里result.mTask.finish(result.mData[0]);就很清楚了,其实就是调用的AsynTask的finish方法,在这个方法里调用了onPostExecute,并且把这个任务的状态设置为完成状态,至此整个任务就算完成了,大家可以自己去看看finish里的代码。这个finish方法是在Handler里执行的,也就是在UI线程执行的,所以我们可以在这里做更新UI的操作。
再来看看SerialExecutor,当初始化该类的时候mActive是空的,会执行scheduleNext,其实这里是从线程队列中取出一个任务然后交给线程池去执行。先暂且不管线程池。还来看SerialExecutor的execute方法,当第一个任务执行完之后mActive不为空,所以当再次执行scheduleNext时在finally里调用的,也就是说如果前面的任务没有执行完,下一个任务不会执行,所以当有多个任务的时候,AsynTask是单线程调用的,效率不是很高,虽然有线程池机制。
相关文章推荐
- Android MVP设计的简单理解
- Android 数据操作之SQLiteDatabase
- android 图片压缩
- 笔记 Android广播初使用
- android 百度地图
- Android程序安装后应用图标不显示
- Android几种弹窗的实现
- Android Studio Ndk 编程
- 【Android】AlarmManager 实现提醒一次,每天提醒,周自定义提醒,月自定义提醒
- Android Studio 导入项目说明
- Using Multiple Android Studio Versions
- Android 自定义View高级特效,神奇的贝塞尔曲线
- 笔记 Android的Fragment初使用
- Android程序中价格的处理
- Realm for Android 快速入门
- Android开源项目分类汇总(七)优秀项目
- android6.0 statusbar 通知栏颜色
- Android Studio使用总结 [未完待续]
- (4.6.9)Android属性allowBackup安全风险浅析
- Android开源项目分类汇总(六)工具库