Files
2026-01-15 11:53:37 +08:00

297 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
}
```
### 方案2ExecutorService
```java
// 使用线程池
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(() -> {
// 后台执行
String result = loadData();
// 主线程更新 UI
runOnUiThread(() -> {
updateUI(result);
});
});
```
### 方案3RxJava
```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
- 在主线程更新 UIonPostExecute、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年*