基础篇-Android异步机制,AsynaTask源码解析与Handler对比
来源:互联网 发布:张悬 知乎 编辑:程序博客网 时间:2024/05/06 08:14
一.Android的异步机制
在Android中实现异步任务机制有两种方式,Handler和AsyncTask。
(1)Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向对应线程发送消息,完成事件处理,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,对多线程进行精确的控制复杂。
(2)1.5中引入AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。它内部是基于handler实现,加入了多线程任务的控制。AsyncTask是对Thread+Handler良好的封装轻量级异步类。可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
(3)优缺点对比:
AsyncTask:简单,便捷。使用轻量级快速更新界面。
Handler:灵活,过程控制精细。可以自定义实现多种线程,对执行过程更加控制比较精细。
至于实际情况下,根据个人习惯来谈谈:
AsyncTask轻量,简单便捷,那么在对整个过程的控制要求不是很复杂精细的情况下使用,比如:层做过一个点餐,菜品飞到购物车的动画效果。比如我们每点一道菜,需要菜的小图,飞行轨迹到达购物车图标所在的地方。飞行轨迹动画一般几百毫秒,那么在点了一道菜,正在飞往购物车,有点一下,这样屏幕上,应该是有一串菜品飞往购物车的轨迹更新,但是这个过程中可能存在一些复杂数据等操作,那么我们就需要把这些并行计算放到异步线程中去操作,然后快速更新UI界面上其对应的动画模块的属性。线程池并发执行,避免计算耗时,至浪费时间,渲染卡顿,性能问题等。这种过程如果利用Handler机制实现,控制将比较繁琐。
当然AsyncTask是Runnable和Handler封装的轻量类。那么其适用性就受到了限制。
实际适用中,我们可以自定义Thread,封装Handler来处理我们特定的过程。比如自定义一个空间,里面异步消息处理当然是Handler来处理,封装后的AsyncTask根本不能处理。看到网上有人在讨论他们的性能等问题,我只想说,虽然AsyncTask是轻量级实现,但是毕竟是自己封装的一些东西进去。没有基础Handler的性能高,但应该是很微小的一点吧。所以具体使用看实际情况与偏好吧O(∩_∩)O~,下面来带大家看看;AsyncTask到底是如何实现的。
二.AsyncTask源码解析
1.基本用法
首先来看一下AsyncTask的基本用法,由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。
在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:
(1). Params
在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
(2). Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
(3). Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
我们还需要去重写AsyncTask中的几个方法才能完成对任务的定制。经常需要去重写的方法有以下四个:
(1). onPreExecute()
这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
(2). doInBackground(Params...)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。
(3). onProgressUpdate(Progress...)
当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
(4). onPostExecute(Result)
当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
class testTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPreExecute() {
showMyShortTip("准备工作");
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int value = test();
publishProgress(value);
if (value >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
showMyShortTip("主线程当前进度:"+values);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
showMyShortTip("执行成功");
} else {
showMyShortTip("执行失败");
}
}
}
@Override
protected void onPreExecute() {
showMyShortTip("准备工作");
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int value = test();
publishProgress(value);
if (value >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
showMyShortTip("主线程当前进度:"+values);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
showMyShortTip("执行成功");
} else {
showMyShortTip("执行失败");
}
}
}
new testTask().execute();
2.AsyncTask源码分析
从执行过程,我们看一看到在启动某一个任务之前,要先new出它的实例,然后在调用Execute()执行。
那么先来解析构造函数,在来看执行过程。
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);
}
}
};
}
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);
}
}
};
}
如上所示并没有任何具体的逻辑会得到执行,只是初始化了两个变量,mWorker和mFuture,并在初始化mFuture的时候将mWorker作为参数传入。mWorker是一个Callable对象,mFuture是一个FutureTask对象(继承了Runable接口,后续run()方法执行,后面再详解),这两个变量会暂时保存在内存中,稍后执行会用到它们。
关于执行execute方法的代码。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
return executeOnExecutor(sDefaultExecutor, params);
}
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;
}
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;
}
这里率先调用了onPreExecute(),我们可以在主线程中先执行预备开始的操作。
将执行时的参数,传入mworker,由构造函数,可知,mFuture中有mWorker的引用,那么参数也传入,继承了Runable接口的类中,之后线程池调用执行。
显而易见关于后台任务执行方法 doInBackground(Params…),是在mWorker的接口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));
}
};
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
并且将执行结构通过postResult,去分发响应,在在postresult'方法。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
通过sHandler,进行消息响应。
或者是调用了publicProgress来更新进度
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
在来看Handler的定义。
private static final InternalHandler sHandler = new InternalHandler();
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;
}
}
}
@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;
}
}
}
首先根据标记判断,消息类型,这里只有2中,返回执行结果或返回执行进度,这里返回执行结构,那么我们在来看下AsyncTask的finish()方法定义。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果取消,那么执行取消操作,不是的话,就调用我们重写的onPostExecute,来进行结果处理。进行进度更新的也是一样。
那么引起这一系列处理是,mWorker的call()。接下来,继续看什么时候调用了这个方法呢。
现在来看看线程池执行mFuture的具体过程。
exec.execute(mFuture);
默认的线程池是这个
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);
}
}
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);
}
}
}
看到里面有一个双端队列ArrayDeque,来每次offer新加一个新建Runnable添加进队列,里面阻塞执行run方法,,不管成功与否,只有结束时,才去执行下一个。第一次执行的时候,mActivi当前活跃Runnable肯定为空,需要初始启动。这样以串行读取执行的方式,来模拟单线程池模式。
接下来我们继续去看mFuture实现的Runnable接口,run()方法是如何实现的。
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
Params[] mParams;
}
看mWorker的实现,就是实现Callable接口,并且缓存了parems参数
private final FutureTask<Result> mFuture;
在来看Future的构造函数:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
其实就是将Callable接口实现,传递给FutureTask去执行,这边在来关注run()方法的实现。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
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);
}
}
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
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);
}
}
那么介绍到这里,基本AsyncTask的基本执行流程的代码算是介绍介绍完了。接下来随便谈谈AsyncTask的一些
关于一些扩展需要注意的点:
SerialExecutor也是AsyncTask在3.0版本以后做了最主要的修改的地方,它在AsyncTask中是以常量的形式被使用的,因此在整个应用程序中的所有AsyncTask实例都会共用同一个SerialExecutor。
如果我们希望一些任务能够并发执行,我们可以自己定义线程池的规则,后调用执行。
可以看到,这里规定同一时刻能够运行的线程数为5个,线程池总大小为128。也就是说当我们启动了10个任务时,只有5个任务能够立刻执行,另外的5个任务则需要等待,当有一个任务执行完毕后,第6个任务才会启动,以此类推。而线程池中最大能存放的线程数是128个,当我们尝试去添加第129个任务时,程序就会崩溃。
Executor exec = new ThreadPoolExecutor(5, 128, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new testTask().executeOnExecutor(exec);
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new testTask().executeOnExecutor(exec);
2 0
- 基础篇-Android异步机制,AsynaTask源码解析与Handler对比
- android handler机制源码解析【异步回调】
- 异步消息处理机制Handler源码解析
- Android Handler机制 源码解析
- Android Handler机制源码解析
- android handler机制源码解析
- Android源码基础解析之异步消息处理机制
- Android基础:异步消息处理机制Handler
- Android:异步消息Handler源码解析
- 【 Android】handler异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- [Android] 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- 带你从源码看Android Handler 异步消息处理机制完全解析
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android消息机制Handler源码简单解析
- Q56:链表中环的入口结点
- 二叉树------寻找二叉树中两个结点的最近公共祖先
- python实现自动监控网站并发送邮件告警
- [刷题]算法竞赛入门经典(第2版) 5-8/UVa230 - Borrowers
- javascript功能插件大集合,写前端的亲们记得收藏
- 基础篇-Android异步机制,AsynaTask源码解析与Handler对比
- obs 0.15.4 编译
- FactoryBean的实现原理与作用
- POJ-1274The Perfect Stall,二分匹配裸模板题
- javaee之hibernate的缓存与注解
- CodeForce 710E - Generate a String(dp)
- TCP链接(三次握手)和释放(四次握手)
- 玩转四旋翼无人机(四元数)
- IAR版本不兼容导致无法正常打开工程文件--解决方法