前言:
在Android应用程序开发中,异步操作是非常常见的需求。比如,我们可能需要在后台线程中执行网络请求、数据库操作或者其他耗时的任务,而不阻塞UI线程。为了实现这些异步操作,Android提供了多种方式,其中之一就是使用AsyncTask类。
1.什么是AsyncTask?
AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。(两个线程池+Handler)
2.介绍AsyncTask类的泛型参数和核心方法
AsyncTask是一个抽象的泛型类,它提供了Params,Progress和Result这三个泛型参数。
public abstract class AsyncTask<Params, Progress, Result>
其中,
- 🟨Params表示参数的类型
- 🟨Progress表示后台任务的执行进度和类型
- 🟨Result表示后台任务的返回结果
AsyncTask类提供了四个核心方法(按照执行顺序介绍):
1️⃣onPreExecute():在主线程中执行,用于准备工作。
2️⃣doInBackground(Params...params):在线程池中执行,用于执行异步任务。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法调用onProgressUpdate方法。
3️⃣onProgressUpdate(Progress...values):在主线程中执行,当后台任务的执行进程发送变化时此方法会被调用。
4️⃣onPostExecute(Result result):在主线程中执行,在异步任务执行之后,此方法会被调用。
AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled会被调用,这个时候,onPostExecute则不会被调用。
3.如何使用AsyncTask?
使用AsyncTask的步骤:
🔶步骤一:继承AsyncTask类,并实现它的几个回调方法,比如doInBackground()方法用来执行后台任务,onPostExecute()方法用来更新UI。
🔶步骤二:在UI线程中创建AsyncTask的实例,并调用execute()方法来启动异步操作。
示例:
在Activity中,创建一个子类来继承AsyncTask,完成以下任务:
1.展示ProgressDialog
2.发送网络请求
3.关闭ProgressDialog
代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AsyncTask_test().execute("");
}
public static ProgressDialog dialog;
public class AsyncTask_test extends AsyncTask<String,Integer,Long> {
@Override
protected void onPreExecute() {
dialog=ProgressDialog.show(MainActivity.this,"", "努力加载中");
}
@Override
protected Long doInBackground(String... strings) {
OkHttpClient okHttpClient = new OkHttpClient();
Request request=new Request.Builder()
.url("https://www.httpbin.org/get?a=1&b=2")
.build();
Response response= null;
try {
response = okHttpClient.newCall(request).execute();
if(!response.isSuccessful()){
Log.e("xxx","网络请求失败"+response);
}
String responsedata=response.body().string();
if(responsedata!=null){
Log.e("xxx","输出:"+responsedata);
}
} catch (IOException e) {
Log.e("xxx","报错"+e);
throw new RuntimeException(e);
}
return null;
}
@Override
protected void onPostExecute(Long aLong) {
if(dialog!=null){
dialog.dismiss();
}
super.onPostExecute(aLong);
}
}
}
AsyncTask在使用时的注意事项:
🟠AsyncTask的对象必须在主线程中创建。(原因:AsyncTask的handler对象是静态的,Handler对象要切换到主线程,由于静态成员在类加载时就被初始化,因此AsyncTask必须在主线程中加载)
🟠execute方法必须在UI线程调用。
🟠不要在线程中直接调用onPreExecute()、onPostExecute、doInBackground和onProgressUpdate方法。
🟠一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常。
4.AsyncTask的工作原理
工作原理:
➡️当asyncTask执行execute()方法的时候,会先调用onPreExecute()方法。
➡️然后调用SERIAL_EXECUTOR的execute(mFuture),把任务加入到队列的尾部等待执行。
➡️执行的时候调用THREAD_POOL_EXECUTOR的execute(mFuture)方法。
➡️mFuture调用mWorker的call()方法,在call()方法中调用了dolnBackground()方法,并在最后调用了postResult()方法。
➡️postResult()方法也就是通过Handler发送消息给主线程,在主线程中调用AsyncTask的finish()方法,来决定是调用onCancelled()还是onPostExecute()方法。
源码解析:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
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;
}
其中,sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程池开始执行,下面是线程池的执行过程:
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);
}
}
}
当一个AsyncTask任务执行完后,AsyncTask会调用scheduleNext()方法继续执行下一个任务直到所有任务被执行为止,总的来说,默认情况下,AsyncTask是串行执行的。
AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handle:
SerialExecutor:用于任务的排队
THREAD_POOL_EXECUTOR:用于真正地执行任务
Handler:用于将执行环境从线程池切换到主线程
在AsyncTask的构造方法中有如下一段代码,由于FutureTask的run方法会调用mWorker的call方法,因此mWorker的call方法最终会在线程池中执行。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return 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);
}
}
};
}
在mWorker的call方法中,首先将mTaskInvoked设为true,表示当前任务已经被调用过了,然后执行AsyncTask的doInBackground方法,接着将返回值传递给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_POST_RESULT的消息,这个Handler对象的定义如下:
getHandler()获取Handler对象
private Handler getHandler() {
return mHandler;
}
赋值mHandler
private final Handler mHandler;
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
...
}
(1)如果callbackLooper == null,就getMainHandler()
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
(2)如果callbackLooper == Looper.getMainLooper(),就new Handler(callbackLooper)
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
Handler对象收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果AsyncTask被取消执行了,那么就调用onCancelled方法,否则就会调用onPostExecute方法,就可以看到doInBackground的返回结果会传递给onPostExecute方法,到这里AsyncTask的整个工作过程就分析完毕了。
总结
通过本篇博客,我们了解了AsyncTask的工作原理和如何在Android应用程序中使用它来进行异步操作。AsyncTask提供了一种简单而强大的方式来管理异步任务,并在UI线程中更新UI,是Android开发中不可或缺的工具之一。希望本篇博客能帮助你更好地理解和使用AsyncTask。