当涉及到在 Android 应用程序中处理耗时操作时,如网络请求、数据库访问、IO 操作等,使用异步线程框架是一种常见的方式。异步线程框架允许将这些耗时的操作放在后台线程执行,从而避免阻塞主线程,提高应用程序的响应速度和用户体验。在 Android 开发中,有多种异步线程框架可供选择,如 AsyncTask、Kotlin 协程、Executor 和 RxJava等。这些框架提供了不同的方式来处理异步操作,并具有各自的优势和用途。以下是对 AsyncTask、Kotlin 协程和 Executor 、RxJava异步线程框架的简要介绍:
- AsyncTask:是 Android 提供的异步任务处理框架,用于在 UI 线程以外的线程执行耗时操作,然后在 UI 线程更新 UI。它通过封装了线程管理和消息处理机制,简化了在 Android 应用中进行异步任务处理的方式。
- Kotlin 协程:是 Kotlin 语言中的一种异步编程框架,用于在非阻塞的方式下处理异步任务。Kotlin 协程通过使用
suspend
关键字来定义挂起函数,可以在代码中使用类似同步代码的方式来处理异步任务,从而避免了回调地狱(Callback Hell)的问题,提供了更简洁、灵活、可读性强的异步编程模型。 - Executor:是 Java 标准库提供的线程池框架,用于在多线程环境下管理和调度线程执行任务。Executor 框架通过创建线程池来管理线程的生命周期,并提供了各种不同类型的线程池,如固定大小线程池、缓存线程池、单线程线程池等,以便满足不同的业务需求。
- RxJava: 是一款流式编程框架,它基于观察者模式和迭代器模式,提供了一种响应式的编程方式,用于处理异步任务、事件流和数据流等。RxJava 可以帮助开发者简化异步编程的复杂性,提高代码的可读性和可维护性。
接下来详细讲讲它们的用法。
一、AsyncTask
AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务的执行进度的类型,而Result则表示后台任务的返回结果的类型,如果AsyncTask确实不需要传递具体的参数,三个泛型参数可以用void代替。
AsyncTask的声明如下:
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask提供了4个核心方法:
1. onPreExecute(),在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于做一些准备工作。
2.doInBackground(Params...params),在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。此方法需要返回计算结果给onPostExecute方法。
3.onProgressUpdate(Progress...values),在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。
4.onPostExecute(Result result),在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。
上面这几个方法,onPreExecute先执行,接着是doInBackgroud,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled()方法会被调用,这个时候onPostExecute则不会被调用。下面提供一个典型的示例,如下所示。
import android.os.AsyncTask;
public class MyAsyncTask extends AsyncTask<Void, Integer, String> {
// 预处理操作
@Override
protected void onPreExecute() {
super.onPreExecute();
// 在主线程中执行,可以更新UI,例如显示进度条等
}
// 后台任务
@Override
protected String doInBackground(Void... voids) {
// 在后台执行耗时操作,不在主线程中执行
// 可以执行网络请求、数据库操作等
return "任务执行结果"; // 返回任务结果
}
// 进度更新操作
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// 在主线程中执行,可以更新UI,例如更新进度条等
}
// 任务完成操作
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// 在主线程中执行,可以更新UI,例如显示结果等
}
}
// 在使用时,可以通过以下方式执行异步任务:
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute(); // 启动异步任务
//取消异步任务:
myAsyncTask.onCancelled();
二、kotlin协程
但是,AsyncTask 是一个在 Android 平台上已经过时的类,自从 Android API 级别 30 起已被弃用。推荐使用更现代的异步任务处理方式,如 Kotlin 的协程或者 Java 的 Executor 框架。
以下是使用 Kotlin 协程的示例代码:
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() {
// 启动一个协程
GlobalScope.launch {
println("协程任务开始")
val result = fetchData() // 模拟耗时操作
println("协程任务结束,结果:$result")
}
println("主线程任务继续执行")
// 使用协程进行并发任务
runBlocking {
val deferred1 = async { fetchData() }
val deferred2 = async { fetchData() }
val result1 = deferred1.await()
val result2 = deferred2.await()
println("并发任务结果:$result1, $result2")
}
}
suspend fun fetchData(): String {
delay(1000) // 模拟耗时操作
return "数据"
}
以上代码使用了 Kotlin 协程,通过 launch
函数在全局范围内启动了一个协程,并在其中执行了一个耗时操作。同时,使用 async
函数创建了两个并发的协程任务,并使用 await
函数来等待这两个任务的完成,最终将结果打印出来。
Kotlin 协程是一种现代的异步任务处理方式,提供了更强大、更灵活、更简洁的异步编程模型,适用于 Android 平台以及其他 JVM 环境。
三、Executor
以下是使用 Java 的 Executor框架的示例代码:
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorExample {
public static void main(String[] args) {
// 创建一个单线程 Executor
Executor executor = Executors.newSingleThreadExecutor();
// 提交一个任务给 Executor 执行
executor.execute(() -> {
System.out.println("任务开始");
String result = fetchData(); // 模拟耗时操作
System.out.println("任务结束,结果:" + result);
});
System.out.println("主线程任务继续执行");
// 创建一个线程池 Executor
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 提交多个任务给 ExecutorService 执行
Future<String> future1 = executorService.submit(() -> fetchData());
Future<String> future2 = executorService.submit(() -> fetchData());
try {
String result1 = future1.get();
String result2 = future2.get();
System.out.println("任务1结果:" + result1);
System.out.println("任务2结果:" + result2);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭 ExecutorService
executorService.shutdown();
}
public static String fetchData() {
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return "数据";
}
}
以上代码使用了 Java 的 Executor 框架,通过 Executors
类创建了一个单线程 Executor 和一个线程池 ExecutorService,并分别提交了任务给 Executor 和 ExecutorService 执行。通过 Future
对象可以获取异步任务的结果,最终将结果打印出来。注意在使用 ExecutorService 后要调用 shutdown()
方法关闭线程池。
四、RxJava
RxJava 的核心概念包括:
- Observable(被观察者):代表一个数据流的源头,可以发出多个数据项、错误或完成的信号。
- Observer(观察者):用于订阅 Observable,并对 Observable 发出的数据项、错误和完成信号进行处理。
- Operator(操作符):用于对 Observable 进行转换、过滤、组合等操作,生成一个新的 Observable。
- Scheduler(调度器):用于控制 Observable 和 Observer 所运行的线程,例如在主线程或后台线程中执行。
下面是一个简单的 RxJava 示例代码:
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
public class RxJavaExample {
public static void main(String[] args) {
// 创建一个 Observable,发出 1、2、3 三个数据项
Observable<Integer> observable = Observable.just(1, 2, 3);
// 创建一个 Observer
Observer<Integer> observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("onSubscribe");
}
@Override
public void onNext(Integer value) {
System.out.println("onNext: " + value);
}
@Override
public void onError(Throwable e) {
System.out.println("onError: " + e.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
};
// 订阅 Observable,并注册 Observer
observable.subscribe(observer);
}
}
以上代码创建了一个 Observable,发出了三个数据项,然后通过一个 Observer 订阅了这个 Observable,并实现了 Observer 的四个回调方法,分别处理了订阅、数据项、错误和完成信号。当 Observable 发出数据项时,会触发 Observer 的 onNext 方法,将数据项传递给 Observer 进行处理。
RxJava 还提供了丰富的操作符,例如 map、filter、flatMap、merge 等,可以用于对 Observable 进行转换、过滤、组合等操作,从而实现更复杂的异步编程逻辑。RxJava 在 Android 开发中也得到了广泛应用,例如用于处理网络请求、数据库操作、UI 事件处理等场景,可以大大简化异步编程的代码复杂性。