注意事项:
- 参数:
AsyncTask<Params,Progress,Result>:Void,Integer,String,Object等,可以使任意类型或封装的对象。
AsyncTask定义了三种泛型类型 Params,Progress和Result。
Params 启动任务执行的输入参数--execute()中传入的参数。
Progress 后台任务执行的进度--publishProgress中传入的参数,onProgressUpdate中接收的参数。
Result 后台执行任务最终返回的结果--例如:doInBackgroud中返回的boolean判断执行是否成功。
- 不能在子线程生成Async实例
ASync中的Handler为静态变量,类加载的时候生成,如果在子线程中new Async,那么Handler也会new,此时子线程new Handler之前没有prepeare会报错。
- execute只能在UI线程调用?
如果onPreExecute没有操作UI,其实也是可以的调用的。
- AsyncTask是串行执行的,多个任务执行的时候一个一个等待。但是注意,每次execute操作,将任务封装放入队列,无论是等待还是执行,在execute的时候,就马上调用onPreExecute了。有可能该任务需要等待,但是该任务下的onPreExecute方法已经执行了。
- AsyncTask默认是串行的,也可以并行操作
mAsyncTask = new MyAsyncTask(myCount);
mAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,myCount+"");
"AsyncTask并不适合进行特别耗时的后台任务,对特别耗时的任务,建议使用线程池。--开发艺术探索上所写,但是还并未理解"
可能是因为:多个任务时特别耗时的任务会影响后面的任务迟迟不能执行。用线程池并发的话,就没这样的问题了。
- 一个AsyncTask对象,只能执行一次execute,前面分析源码的时候已经验证过了,Running或者Finished的时候再执行都会报错。
- 无论在任何线程,任何地方使用AsyncTask,因为该类内部的sDefaultExecutor是static类型,都将只有一个线程池对象。所以,AsyncTask的任务都是在这一个线程池中执行。
所以,任何线程,任何地方,单次或多次调用AsyncTask执行,都是会放入队列,串行执行的。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
AsyncTask 缺陷/坑:
AsyncTask有多个版本,多种实现,不具体分析。
总之,在3.0以前,最大支持128个线程的并发,10个任务的等待。并发执行,不用等待。超过138个任务同时执行,会发生异常:java.util.concurrent.RejectedExecutionException 。
在3.0以后,无论有多少任务,都会在其内部单线程一个一个执行;异常问题:
Activity退出时,记得在onDestroy中cancle,并在AsyncTask做isCancel检查操作,确定Async代码是否执行。否则,有坑能退出Activity的时候Async还没有执行完,Async执行完要更新UI的时候View已经销毁。
- 内存泄漏问题:
1.Java特性,AsyncTask类在Activity是非静态内部类的时候,默认持有外部类Activity的引用。
2.AsyncTask持有Activity中的变量,如View。
如何避免:
静态内部类。activity若引用,使用activity变量的时候判断null。例如前篇,Handler防止内存泄漏一样。
取消操作任务操作时,AsyncTask不能中断的处理。
cancel的时候,并不能中断已经开始的任务,因为不能中断正在执行的Thread(但是测试的可以中断正在执行的Async,看下面"不确定",这里就按大部分人说的不能中断的情况下)。
//AsyncTask方法
public final boolean cancel(boolean mayInterruptIfRunning) {
//标记
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
//FutureTask方法
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 {
//最后调用onCancle()方法
finishCompletion();
}
return true;
}
mCancelled.set(true);只是在AsyncTask中一个标记,说明是否执行过中断操作,至于有没有中断成功isCancelled()的返回值并不能说明。 t.interrupt();才是执行中断线程的主要代码,现在并不确定该方法是否能中断线程(网上说不能中断,而我测试可以中断)。
解决办法:
- 在AsyncTask执行的代码中,判断是否中断,isCancelled();
- 如果后台任务有频繁的while操作,可以添加Thread.sleep(1)。因为interrupt的时候,会使阻塞的线程抛异常,捕获异常后return结束doInBackgroud方法。
不确定:
- 中断任务:
Thread/AsyncTask不能中断。Java线程在执行的时候,并不能中断该线程,同样AsyncTask也是。但是测试的结果是,Thread不能中断,AsyncTask可以中断。
按说,它们都是把执行的代码封装到了Runnable,开子线程执行。但测试就是Thread中断了,AsyncTask没有中断。
//testThread.interrupt();不能中断
public class TestRunnable implements Runnable {
private static final String TAG = "TestRunnable";
private int count = 0;
@Override
public void run() {
while (count < 1000) {
Log.e(TAG, "run: count=" + count);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//interrupt会使阻塞的线程抛该异常。也可以利用这个特性,中断任务。抛异常的时候return。
// return;
}
count++;
}
}
}
// mAsyncTask.execute(count + ""); 按说也因该不能中断的,但是,测试的时候就是中断了啊。
@Override
protected Boolean doInBackground(String... params) {
while (currentProgress <= 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//return false;
}
currentProgress++;
}
return true;
}