297 lines
5.9 KiB
Markdown
297 lines
5.9 KiB
Markdown
|
|
# AsyncTask
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
- [AsyncTask原理](#asynctask原理)
|
|||
|
|
- [AsyncTask生命周期](#asynctask生命周期)
|
|||
|
|
- [AsyncTask执行流程](#asynctask执行流程)
|
|||
|
|
- [AsyncTask问题](#asynctask问题)
|
|||
|
|
- [AsyncTask替代方案](#asynctask替代方案)
|
|||
|
|
- [AsyncTask最佳实践](#asynctask最佳实践)
|
|||
|
|
- [面试常见问题](#面试常见问题)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask原理
|
|||
|
|
|
|||
|
|
### AsyncTask 简介
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// AsyncTask:异步任务类
|
|||
|
|
// 在后台线程执行任务,在主线程更新 UI
|
|||
|
|
// 已废弃(Android 11+),推荐使用协程或 ExecutorService
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### AsyncTask 结构
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public abstract class AsyncTask<Params, Progress, Result> {
|
|||
|
|
// Params:参数类型
|
|||
|
|
// Progress:进度类型
|
|||
|
|
// Result:结果类型
|
|||
|
|
|
|||
|
|
// 在后台线程执行
|
|||
|
|
protected abstract Result doInBackground(Params... params);
|
|||
|
|
|
|||
|
|
// 在主线程执行(任务开始前)
|
|||
|
|
protected void onPreExecute() { }
|
|||
|
|
|
|||
|
|
// 在主线程执行(进度更新)
|
|||
|
|
protected void onProgressUpdate(Progress... values) { }
|
|||
|
|
|
|||
|
|
// 在主线程执行(任务完成后)
|
|||
|
|
protected void onPostExecute(Result result) { }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask生命周期
|
|||
|
|
|
|||
|
|
### 生命周期方法
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public class MyAsyncTask extends AsyncTask<String, Integer, String> {
|
|||
|
|
@Override
|
|||
|
|
protected void onPreExecute() {
|
|||
|
|
super.onPreExecute();
|
|||
|
|
// 主线程:任务开始前
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected String doInBackground(String... params) {
|
|||
|
|
// 后台线程:执行任务
|
|||
|
|
for (int i = 0; i < 100; i++) {
|
|||
|
|
publishProgress(i); // 更新进度
|
|||
|
|
}
|
|||
|
|
return "Result";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected void onProgressUpdate(Integer... values) {
|
|||
|
|
super.onProgressUpdate(values);
|
|||
|
|
// 主线程:进度更新
|
|||
|
|
int progress = values[0];
|
|||
|
|
progressBar.setProgress(progress);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected void onPostExecute(String result) {
|
|||
|
|
super.onPostExecute(result);
|
|||
|
|
// 主线程:任务完成
|
|||
|
|
textView.setText(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected void onCancelled() {
|
|||
|
|
super.onCancelled();
|
|||
|
|
// 主线程:任务取消
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask执行流程
|
|||
|
|
|
|||
|
|
### 执行流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. execute() → 创建任务
|
|||
|
|
2. onPreExecute() → 主线程执行
|
|||
|
|
3. doInBackground() → 后台线程执行
|
|||
|
|
4. publishProgress() → 更新进度
|
|||
|
|
5. onProgressUpdate() → 主线程更新 UI
|
|||
|
|
6. onPostExecute() → 主线程执行(任务完成)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 执行示例
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 创建并执行
|
|||
|
|
MyAsyncTask task = new MyAsyncTask();
|
|||
|
|
task.execute("param1", "param2");
|
|||
|
|
|
|||
|
|
// 取消任务
|
|||
|
|
task.cancel(true);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask问题
|
|||
|
|
|
|||
|
|
### 1. 内存泄漏
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// ❌ 问题:AsyncTask 持有 Activity 引用
|
|||
|
|
public class MainActivity extends AppCompatActivity {
|
|||
|
|
private MyAsyncTask task;
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|||
|
|
super.onCreate(savedInstanceState);
|
|||
|
|
task = new MyAsyncTask();
|
|||
|
|
task.execute();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果 Activity 销毁,但 AsyncTask 还在执行
|
|||
|
|
// Activity 无法被回收
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 配置变更问题
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// ❌ 问题:屏幕旋转时 Activity 重建
|
|||
|
|
// AsyncTask 持有旧 Activity 引用
|
|||
|
|
// 可能导致崩溃或内存泄漏
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 串行执行
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// AsyncTask 默认串行执行
|
|||
|
|
// 多个 AsyncTask 按顺序执行
|
|||
|
|
// 可能影响性能
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 已废弃
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// Android 11+ 已废弃 AsyncTask
|
|||
|
|
// 推荐使用协程或 ExecutorService
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask替代方案
|
|||
|
|
|
|||
|
|
### 方案1:协程(推荐)
|
|||
|
|
|
|||
|
|
```kotlin
|
|||
|
|
// 使用协程
|
|||
|
|
lifecycleScope.launch {
|
|||
|
|
val result = withContext(Dispatchers.IO) {
|
|||
|
|
// 后台执行
|
|||
|
|
loadData()
|
|||
|
|
}
|
|||
|
|
// 主线程更新 UI
|
|||
|
|
updateUI(result)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案2:ExecutorService
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 使用线程池
|
|||
|
|
ExecutorService executor = Executors.newCachedThreadPool();
|
|||
|
|
executor.execute(() -> {
|
|||
|
|
// 后台执行
|
|||
|
|
String result = loadData();
|
|||
|
|
|
|||
|
|
// 主线程更新 UI
|
|||
|
|
runOnUiThread(() -> {
|
|||
|
|
updateUI(result);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案3:RxJava
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 使用 RxJava
|
|||
|
|
Observable.fromCallable(() -> loadData())
|
|||
|
|
.subscribeOn(Schedulers.io())
|
|||
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|||
|
|
.subscribe(result -> {
|
|||
|
|
updateUI(result);
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## AsyncTask最佳实践
|
|||
|
|
|
|||
|
|
### 1. 使用静态内部类
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// ✅ 使用静态内部类避免内存泄漏
|
|||
|
|
private static class MyAsyncTask extends AsyncTask<String, Void, String> {
|
|||
|
|
private WeakReference<MainActivity> activity;
|
|||
|
|
|
|||
|
|
MyAsyncTask(MainActivity activity) {
|
|||
|
|
this.activity = new WeakReference<>(activity);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected String doInBackground(String... params) {
|
|||
|
|
// 执行任务
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
protected void onPostExecute(String result) {
|
|||
|
|
MainActivity act = activity.get();
|
|||
|
|
if (act != null && !act.isFinishing()) {
|
|||
|
|
// 更新 UI
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 及时取消
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@Override
|
|||
|
|
protected void onDestroy() {
|
|||
|
|
super.onDestroy();
|
|||
|
|
if (task != null) {
|
|||
|
|
task.cancel(true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 使用替代方案
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 推荐使用协程或 ExecutorService
|
|||
|
|
// AsyncTask 已废弃
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 面试常见问题
|
|||
|
|
|
|||
|
|
### Q1: AsyncTask 的原理?
|
|||
|
|
|
|||
|
|
**答案:**
|
|||
|
|
- 在后台线程执行任务(doInBackground)
|
|||
|
|
- 在主线程更新 UI(onPostExecute、onProgressUpdate)
|
|||
|
|
- 使用线程池执行任务
|
|||
|
|
|
|||
|
|
### Q2: AsyncTask 的问题?
|
|||
|
|
|
|||
|
|
**答案:**
|
|||
|
|
1. 内存泄漏:持有 Activity 引用
|
|||
|
|
2. 配置变更:屏幕旋转时可能出问题
|
|||
|
|
3. 串行执行:默认串行,可能影响性能
|
|||
|
|
4. 已废弃:Android 11+ 已废弃
|
|||
|
|
|
|||
|
|
### Q3: AsyncTask 的替代方案?
|
|||
|
|
|
|||
|
|
**答案:**
|
|||
|
|
1. **协程**:Kotlin 官方推荐
|
|||
|
|
2. **ExecutorService**:线程池
|
|||
|
|
3. **RxJava**:响应式编程
|
|||
|
|
|
|||
|
|
### Q4: 如何避免 AsyncTask 内存泄漏?
|
|||
|
|
|
|||
|
|
**答案:**
|
|||
|
|
1. 使用静态内部类
|
|||
|
|
2. 使用 WeakReference
|
|||
|
|
3. 及时取消任务
|
|||
|
|
4. 使用替代方案
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*最后更新:2024年*
|