案例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 1. 定义回调接口
public interface ThreadSwitchCallback {
void onSuccess(String result); // 成功回调
void onFailure(Exception error); // 失败回调
void onProgress(int progress); // 进度更新回调
}
// 2. 模拟耗时任务执行器
public class AsyncTaskExecutor {
private final ExecutorService threadPool = Executors.newFixedThreadPool(2);
// 3. 执行异步任务(接受回调参数)
public void executeTask(final String input, final ThreadSwitchCallback callback) {
threadPool.execute(() -> {
try {
// 在工作线程执行耗时操作
for (int i = 0; i <= 100; i += 10) {
Thread.sleep(200); // 模拟工作
callback.onProgress(i); // 进度更新回调
}
// 模拟处理结果
String result = "Processed: " + input.toUpperCase();
// 4. 切换到主线程(UI线程)回调结果
switchToMainThread(() -> callback.onSuccess(result));
} catch (Exception e) {
// 5. 错误处理(切换到主线程)
switchToMainThread(() -> callback.onFailure(e));
}
});
}
// 6. 模拟切换到主线程的方法
private void switchToMainThread(Runnable action) {
// 在实际Android中应使用 new Handler(Looper.getMainLooper()).post(action)
// 这里使用简单模拟
new Thread(() -> {
try {
Thread.sleep(50); // 模拟线程切换延迟
System.out.println("【切换到主线程】");
action.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
// 7. 主程序(模拟Android UI线程)
public class CallbackDemo {
public static void main(String[] args) {
System.out.println("【主线程】启动 - " + Thread.currentThread().getName());
AsyncTaskExecutor executor = new AsyncTaskExecutor();
// 8. 创建回调实现
ThreadSwitchCallback callback = new ThreadSwitchCallback() {
@Override
public void onSuccess(String result) {
System.out.println("【回调结果】" + result + " - 线程: " + Thread.currentThread().getName());
}
@Override
public void onFailure(Exception error) {
System.err.println("【回调错误】" + error.getMessage());
}
@Override
public void onProgress(int progress) {
System.out.println("【进度更新】" + progress + "% - 线程: " + Thread.currentThread().getName());
}
};
// 9. 执行异步任务
System.out.println("【主线程】启动异步任务");
executor.executeTask("Hello Callback", callback);
// 10. 主线程继续执行其他任务
System.out.println("【主线程】继续执行其他任务...");
// 保持程序运行(模拟Android生命周期)
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果示例
【主线程】启动 - main
【主线程】启动异步任务
【主线程】继续执行其他任务...
【进度更新】0% - 线程: Thread-0
【进度更新】10% - 线程: Thread-0
【进度更新】20% - 线程: Thread-0
【进度更新】30% - 线程: Thread-0
【进度更新】40% - 线程: Thread-0
【进度更新】50% - 线程: Thread-0
【进度更新】60% - 线程: Thread-0
【进度更新】70% - 线程: Thread-0
【进度更新】80% - 线程: Thread-0
【进度更新】90% - 线程: Thread-0
【进度更新】100% - 线程: Thread-0
【切换到主线程】
【回调结果】Processed: HELLO CALLBACK - 线程: Thread-1
核心机制解析
1. 回调接口定义
public interface ThreadSwitchCallback {
void onSuccess(String result);
void onFailure(Exception error);
void onProgress(int progress);
}
定义线程切换后需要执行的操作
包含成功、失败、进度更新三种回调类型
2. 线程切换关键实现
private void switchToMainThread(Runnable action) {
new Thread(() -> {
Thread.sleep(50); // 模拟线程切换延迟
System.out.println("【切换到主线程】");
action.run(); // 在主线程执行回调
}).start();
}
回调机制的优缺点
优点:
明确的异步操作分离
支持多状态回调(成功/失败/进度)
兼容各种 Java 版本
线程切换逻辑清晰可见
缺点:
嵌套回调导致"金字塔"代码结构
错误处理分散在不同回调中
需要手动管理线程切换
回调接口定义繁琐(需创建多个接口)
与 Kotlin 协程对比
特性 | Java 回调 | Kotlin 协程 |
---|---|---|
代码结构 | 嵌套回调 | 线性同步风格 |
线程切换 | 手动使用 Handler | 自动通过 Dispatchers |
错误处理 | 分散在各回调 | 集中 try-catch |
并发控制 | 需手动同步 | async/await 简化 |
内存开销 | 多个回调对象 | 共享状态机 |
学习曲线 | 简单直接 | 概念较复杂 |
关键区别:协程本质上也是基于回调机制,但通过编译器将回调转换为状态机,使代码保持线性结构。回调是显式线程切换,协程是隐式线程切换。