AsyncTask解惑
2015-11-19 13:16
344 查看
AsyncTask作为执行后台操作常见的一种实现方式,还是有必要阅读下源码,了解其实现机制的。这里是使用Android4.4的源码
使用AsyncTask的规则(这几点sdk文档都有说明)
1. AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
2. AsyncTask对象必须在UI线程创建
3. execute方法必须在UI线程调用
4. 不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
5. 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
6. AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
7. 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
几个问题
1. AsyncTask为什么要在UI线程中创建和执行
-----AsyncTask的实现原理也是通过worker thread和Handler来实现的,工作线程在汇报工作进度及结果时和UI线程通讯是采用Handler来做的,而这个Handler只能是关联UI线程的Handler
2. AsyncTask为什么不能重用,只能执行一次execute
----这是个规则,AsyncTask源码中有对这个进行判断。
3. 为什么只能执行几秒钟的任务,不能执行耗时的操作。
stackoverflow上有人提出了同样的问题,但是我觉得答案有待商榷,
被选中的答案大概意思是
a. AsyncTask长时间执行任务时,Activity被销毁时,后台任务仍在进行,这样会出现崩溃
b. AsyncTask常被作为内部类使用,当AsyncTask长时间执行时,其外部类对象不能被销毁,易出现内存泄漏
-----我对这个答案有所保留,我们使用WeakRefence或者worker fragment足以解决这些问题。
我认为的原因之一是串行执行的任务如果执行时间过长,其他task就不能及时进行。这样就会让app看上去反应很迟钝。
欢迎补充
4. 这里的串行执行是什么个概念?
----看下AsyncTask代码就知道了
[java] view
plaincopy
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 执行后台任务的入口函数
// sDefaultExecutor是类的静态成员,负责管理同一个进程中所有的AsyncTask串行执行的所有子类对象
// 所以说,不管是ATask还是BTask,一次只有一个task被执行。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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);
}
}
}
5.取消机制是怎么实现的
[java] view
plaincopy
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final FutureTask<Result> mFuture;
public final boolean cancel(boolean mayInterruptIfRunning) {
// 设置标志位
mCancelled.set(true);
// 主要的实现是通过FutureTask来实现的
return mFuture.cancel(mayInterruptIfRunning);
}
FutureTask来实现的,FutureTask实现了Future接口,这个可以查看博客园的文章 http://www.cnblogs.com/dolphin0520/p/3949310.html
6. cancel有个参数mayInterruptIfRunning,怎么解读
------java程序员估计都清楚这个参数的意义,但作为C++出身的我碰到这个还是多少有点疑惑的。工作线程是可能执行一些阻塞的操作的,比如sleep、文件io,mayInterruptIfRunning表示是否中断这些阻塞操作,让工作线程继续往下执行。
使用AsyncTask的规则(这几点sdk文档都有说明)
1. AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
2. AsyncTask对象必须在UI线程创建
3. execute方法必须在UI线程调用
4. 不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
5. 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
6. AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
7. 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
几个问题
1. AsyncTask为什么要在UI线程中创建和执行
-----AsyncTask的实现原理也是通过worker thread和Handler来实现的,工作线程在汇报工作进度及结果时和UI线程通讯是采用Handler来做的,而这个Handler只能是关联UI线程的Handler
2. AsyncTask为什么不能重用,只能执行一次execute
----这是个规则,AsyncTask源码中有对这个进行判断。
3. 为什么只能执行几秒钟的任务,不能执行耗时的操作。
stackoverflow上有人提出了同样的问题,但是我觉得答案有待商榷,
被选中的答案大概意思是
a. AsyncTask长时间执行任务时,Activity被销毁时,后台任务仍在进行,这样会出现崩溃
b. AsyncTask常被作为内部类使用,当AsyncTask长时间执行时,其外部类对象不能被销毁,易出现内存泄漏
-----我对这个答案有所保留,我们使用WeakRefence或者worker fragment足以解决这些问题。
我认为的原因之一是串行执行的任务如果执行时间过长,其他task就不能及时进行。这样就会让app看上去反应很迟钝。
欢迎补充
4. 这里的串行执行是什么个概念?
----看下AsyncTask代码就知道了
[java] view
plaincopy
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 执行后台任务的入口函数
// sDefaultExecutor是类的静态成员,负责管理同一个进程中所有的AsyncTask串行执行的所有子类对象
// 所以说,不管是ATask还是BTask,一次只有一个task被执行。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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);
}
}
}
5.取消机制是怎么实现的
[java] view
plaincopy
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final FutureTask<Result> mFuture;
public final boolean cancel(boolean mayInterruptIfRunning) {
// 设置标志位
mCancelled.set(true);
// 主要的实现是通过FutureTask来实现的
return mFuture.cancel(mayInterruptIfRunning);
}
FutureTask来实现的,FutureTask实现了Future接口,这个可以查看博客园的文章 http://www.cnblogs.com/dolphin0520/p/3949310.html
6. cancel有个参数mayInterruptIfRunning,怎么解读
------java程序员估计都清楚这个参数的意义,但作为C++出身的我碰到这个还是多少有点疑惑的。工作线程是可能执行一些阻塞的操作的,比如sleep、文件io,mayInterruptIfRunning表示是否中断这些阻塞操作,让工作线程继续往下执行。
相关文章推荐
- 使用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