AsyncTask 有助于应用 UI 线程。这个类能让你不被动应用多线程或 Handler,在子线程种执行耗时工作,并在 UI 线程公布后果。
AsyncTask 是一个在不须要开发者间接操作多线程和 Handler 的状况下的帮忙类,实用于短时间的操作(最多几秒)。如需长时间的线程操作,倡议应用多线程包 java.util.concurrent
中的性能,比方线程池。
假如咱们有个须要在后盾线程中运行的异步计算工作,并且后果须要更新 ui。那咱们须要关注 3 个范型参数:Params
,Progress
和 Result
。
再关注 4 个步骤办法:onPreExecute
, doInBackground
, onProgressUpdate
和 onPostExecute
属性介绍
应用 AsyncTask 之前,咱们先看一下它的三个类型。
AsyncTask<Params, Progress, Result>
属性 | 形容 |
---|---|
Params |
执行工作前,传入的参数的类型 |
Progress |
后盾线程执行的时候,用来示意进度的类型 |
Result |
示意执行后果的类型 |
这 3 个类型须要开发者本人指定。比方指定 String, Integer 等。这 3 个类型在前面的办法里会用到。
不必的泛型能够用 Void
示意。例如
private class MyTask extends AsyncTask<Void, Void, Void> {...}
办法介绍
要应用 AsyncTask,必须新建一个类来继承它,并且重写 doInBackground
办法。通常也会重写 onPostExecute
办法。执行异步工作的时候,咱们次要关怀上面这 4 个办法。
办法 | 形容 |
---|---|
onPreExecute() |
执行工作前在 ui 线程调用。通用用来设置工作,比方在界面上显示一个进度条。 |
Result doInBackground(Params... params) |
在 onPreExecute() 完结后立刻调用这个办法。耗时的异步工作就在这里操作。执行工作时传入的参数会被传到这里。异步工作的两头后果在这里能够用 publishProgress 发送到主线程。 |
onProgressUpdate(Progress... values) |
在 ui 线程中执行。后台任务还在进行的时候,这里负责解决进度信息。比方在这显示进度条动画,批改文字显示等。 |
onPostExecute(Result result) |
后台任务完结了调这个办法。它在 ui 线程执行。最初的后果会传到这。 |
AsyncTask 的三种状态
每个状态在一个工作的生命周期中只会被执行一次。
状态 | 形容 |
---|---|
PENDING | 期待(还没有开始执行工作) |
RUNNING | 执行中 |
FINSHED | 实现 |
用法示例
虚构一个计算工作
/**
* 虚构的计算工作
*/
private class CalculationTask extends AsyncTask<Float, Integer, Float> {protected Float doInBackground(Float... inputs) {Log.d(TAG, "doInBackground thread ID =" + Thread.currentThread().getId());
long step = 0;
float result = 0;
for (float f : inputs) {
// 假如这里有一些耗时的操作
result += f;
}
while (step < 5) {
result += step;
step++;
publishProgress((int) step);
}
return result;
}
protected void onProgressUpdate(Integer... progress) {Log.d(TAG, "onProgressUpdate thread ID =" + Thread.currentThread().getId());
Log.d(TAG, "onProgressUpdate:" + progress[0]);
}
protected void onPostExecute(Float result) {Log.d(TAG, "onPostExecute thread ID =" + Thread.currentThread().getId());
Log.d(TAG, "工作执行结束");
}
}
// 执行工作
new CalculationTask().execute(1.2f, 2.3f, 6.3f);
勾销工作
调用 cancel(boolean)
可随时勾销工作。勾销工作后 isCancelled()
会返回 true。
调用这个办法后,后台任务 doInBackground(Object[])
执行结束后会调用 onCancelled(Object)
而不再是 onPostExecute(Object)
。为保障工作能被及时地勾销,在 doInBackground(Object[])
中应该常常查看 isCancelled()
返回值
线程规定 Threading rules
- 异步工作必须从 UI 线程启动
- 必须在 UI 线程实例化 AsyncTask 类
- 必须在 UI 线程调用
execute(Params...)
- 不要手动调用
onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
- 同一个异步工作实例只能被执行一次。反复执行同一个异步工作实例会抛出异样(
IllegalStateException
)。
AsyncTask 相干面试题
1. AsyncTask 是什么?能解决什么问题
2. 谈谈 AsyncTask 的三个泛型参数作⽤
3. 说说 AsyncTask 的原理
结构⽅法中创立了⼀个 WorkRunnable 和⼀个 FutureTask 对象,
在 WorkRunnable 的 Call ⽅法中调⽤ doInBackground ⽅法,并获取 Result 返回值,而后返回调⽤ postResult ⽅法的返回值,创立 FutureTask 时传⼊了 WorkRunnable 对象。
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);
}
}
};
}
postResult ⽅法
getHandler ⽅法获取⾃带 Handler 对象,来获取 Message
private Result postResult(Result result) {@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new
AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
这个外部⾃带 InternalHandler 结构⽅法中传⼊ getMainLooper()返回值,即主线程 Looper,
而后在 handlerMessage ⾥⾯针对 msg.what 别离执⾏了 finish 和 onProgressUpdate ⽅法,其中 finish ⽅法令是调⽤ onCancelled 或 onPostExecute ⽅法
private static final InternalHandler sHandler = new InternalHandler();
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;
}
}
}
private void finish(Result result) {if (isCancelled()) {onCancelled(result);
} else {onPostExecute(result);
}
mStatus = Status.FINISHED;
}
看看 AsyncTask 的 execute ⽅法,返回了 executeOnExecutor 的⽅法,并传⼊ sDefaultExecutor 和 params 为参数,params 即 AsyncTask 的 doInBackground 中传⼊的 params ,
⽽ sDefaultExecutor 是默认的串⾏执⾏器(线程池),⼀个 SerialExecutor 再看看 executeOnExecutor ⽅法,先判断了工作状态,如果是 RUNNING 或 FINISHED,则会抛出异样,
而后会把以后状态从 PENDING 改为 RUNNING,把⼊参 params 传到 WorkRunnable 对象中,再调⽤传⼊的 sDefaultExecutor 的 execute ⽅法,传⼊ mFuture 为参数
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 ⽅法中调⽤ mTasks 的 offer ⽅法增加⼀个工作到缓存队列中,在 run ⽅法中就调⽤了前⾯传⼊的 mFuture 的 run ⽅法,
而后执⾏ THREAD_POOL_EXECUTOR 的 execute ⽅法,工作的理论执⾏就在这,THREAD_POOL_EXECUTOR 就是⼀个线程池
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);
}
}
}
4. 你感觉 AsyncTask 有不⾜之处吗?
AsyncTask 使⽤起来⽐较轻量,然而⾃身也存在⼀些问题。
次要体现在:
- cancel ⽅法实现不是很好。如果你调⽤了 AsyncTask 的 cancel(false) ⽅法,doInBackground() 依然会执⾏到⽅法完结,只是不会去调⽤ onPostExecute() ⽅法,然而实际上也是让程序执⾏了没有意义的操作。如果调⽤ cancel(true),mayInterruptIfRunning 设置为 true,会使工作尽早完结,然而如果 doInBackground() 有不可被打断的⽅法,就会生效,⽐如 BitmapFactory.decodeStream() 操作。
- 内存泄露,在 Activity 中使⽤⾮动态匿名外部类 AsyncTask 类,因为 Java 外部类的特点,外部类持有外部类引⽤,⽽因为 AsyncTask ⽣命周期可能⽐ Activity 的,当 Activity 销毁时,AsyncTask 还在执⾏,因为 AsyncTask 持有 Activity 的引⽤,导致 Activity 对象⽆法回收,进⽽产⽣内存泄露。
- 后果失落,当屏幕旋转等造成 Activity 新创建时 AsyncTask 数据失落的问题。当 Actviity 销毁并创立新的收,还在运⾏的 AsyncTask 会持有⼀个 Activity 的⾮法引⽤,即之前 Activity 的实例,导致 onPostExecute() ⽅法⽆效。
- 串⾏,并⾏多版本不⼀致.1.6 之前为串⾏,1.6-2.3 为并⾏,3.0 之后⼜改为串⾏,然而能够通过 executeOnExecutor() 实现并⾏解决
Android 零根底入门教程视频参考