AsyncTask是Android中用来执行异步执行耗时操作的框架。
1、AsyncTask使用
继承AsyncTask,并且实现doInBackground方法。其中doInBackground中进行耗时操作,比如网络请求,文件读取等。
class DownloadTask : AsyncTask<URL, Int, Long>() {
override fun doInBackground(vararg params: URL?): Long {
//执行background
return 1000L
}
override fun onPreExecute() {
//执行之前
super.onPreExecute()
}
override fun onPostExecute(result: Long?) {
//执行之后
super.onPostExecute(result)
}
override fun onProgressUpdate(vararg values: Int?) {
//更新进度
super.onProgressUpdate(*values)
}
}
如下方法执行AsyncTask,execute方法必须在ui线程中进行,
DownloadTask().execute(URL("https://baidu.com"))
2、AsyncTask实现
从AsyncTask的execute方法进行分析
1、execute
启动AsyncTask的方法,源码如下
public final AsyncTask<Params, Progress, Result> execute(Params... 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;
}
AsyncTask默认的Executor是sDefaultExecutor,看下sDefaultExecutor的源码:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new 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);
}
}
}
sDefaultExecutor的实现类是SerialExecutor,SerialExecutor中用task来保存任务,并且通过task中上一个任务执行时完时主动调起下一个任务进行执行,来保证执行顺序。具体的执行任务的是THREAD_POOL_EXECUTOR。
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
上面创建THEAD_POOL_EXECUTOR,主要看下rejectedExecutionHandler,sRunOnSerialPolicy
private static final RejectedExecutionHandler sRunOnSerialPolicy =
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
synchronized (this) {
if (sBackupExecutor == null) {
sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
sBackupExecutor = new ThreadPoolExecutor(
BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
sBackupExecutor.allowCoreThreadTimeOut(true);
}
}
sBackupExecutor.execute(r);
}
};
由上面可见,THEAD_POOL_EXECUTOR是核心线程数为1,最大线程数为20的线程池,当线程池执行rejected的时候会使用sBackupExecutor来执行被reject的任务。sBackupExecutor是核心线程数和最大线程数都为5的线程池,并且核心线程数可以被回收,避免空线程等待。
2、exec.execute(mFuture);
在上面executeOnExecutor方法中执行完onPreExecute后会调用exec.execute(mFuture)这个方法是用来执行后台耗时操作对应AsyncTask中的doInBackground方法,其中mFuture,是一个FutureTask
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是一个WorkerRunnable,源码如下,doInBackground方法就是在worker的call方法中被调用的。
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
WorkerRunnable实现Callable接口
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
看下postResultIfNotInvoked方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
postResult方法源码如下:
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把message抛到ui线程中执行,
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
result.mTask.finish方法如下
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
3、AsyncTask问题
google官方已经把AsyncTask废弃了在AsyncTask源码的官方注释中有说明废弃的原因
that would cause Context leaks, missed callbacks, or crashes on configuration changes. It also has inconsistent behavior on different
versions of the platform, swallows exceptions from { @code doInBackground}, and does not provide
much utility over using { @link Executor}s directly.
1、生命周期问题与内存泄露
AsyncTask会一直执行,直到doInBackground()方法执行完毕。如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会持有对Activity的引用,如果在销毁activity的时候没有取消正在运行的AsyncTask,这会导致Activity没法被回收,从而导致内存泄露。
2、结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
3、处理不当容易导致任务阻塞
所以如果一个AsyncTask的doInBackGround方法中存在着一个无限循环没有正确处理,导致这个AsyncTask的doInBackGround方法一直运行,那么这会导致同一个进程中其他的AsyncTask的任务无法执行。
4、其他
1、Future
Future是接口,有如下的方法,子类继承Future接口会重新这些方法,Future的子类有FutureTask.
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
2、Callable
Callable是一个接口,call方法返回值,
public interface Callable<V> {
V call() throws Exception;
}
3、FutureTask
FutureTask 为 Future 提供了基础实现,如获取任务执行结果(get)和取消任务(cancel)等。如果任务尚未完成,获取任务执行结果时将会阻塞。一旦执行结束,任务就不能被重启或取消(除非使用runAndReset执行计算)。FutureTask 常用来封装 Callable 和 Runnable,也可以作为一个任务提交到线程池中执行。除了作为一个独立的类之外,此类也提供了一些功能性函数供我们创建自定义 task 类使用。FutureTask 的线程安全由CAS来保证。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZyAX1tE-1656827041607)(https://tech-proxy.bytedance.net/tos/images/1656827031432_2b64520346dfeb898d3321bb163a4335)]
FutureTask实现了RunnableFuture的接口,如下
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
FutureTask可以通过get方法来拿到执行的结果。
val executor = Executors.newFixedThreadPool(
1
)
val futureTask = FutureTask<String>(object : Callable<String> {
override fun call(): String {
return "good good study"
}
})
executor.execute(futureTask)
val s=futureTask.get()
创建FutureTask的时候会传入一个Callable对象,executor.execute(futureTask)执行时会调用futureTask的run方法,FutureTask的run方法源码如下:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, 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 = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
FutureTask的run方法其实调用了Callable.call方法并且拿到result值。然后通过set方法进行设置,set方法代码如下:
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL);
finishCompletion();
}
}
futureTask.get()实现
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
long startTime = 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING)
Thread.yield();
else if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
else if (q == null) {
if (timed && nanos <= 0L)
return s;
q = new WaitNode();
}
else if (!queued)
queued = U.compareAndSwapObject(this, WAITERS,
q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) {
startTime = System.nanoTime();
if (startTime == 0L)
startTime = 1L;
parkNanos = nanos;
} else {
long elapsed = System.nanoTime() - startTime;
if (elapsed >= nanos) {
removeWaiter(q);
return state;
}
parkNanos = nanos - elapsed;
}
if (state < COMPLETING)
LockSupport.parkNanos(this, parkNanos);
}
else
LockSupport.park(this);
}
}
参考
1、https://pdai.tech/md/java/thread/java-thread-x-juc-executor-FutureTask.html
2、https://developer.android.com/reference/android/os/AsyncTask
|