Dart中回调函数的简单实现
在 Dart 中,回调函数(Callback)是实现异步编程、事件监听或自定义逻辑扩展的核心机制之一。以下给出 3 种常见的实现:
1、基础同步回调(立即执行)
适用于需要立即触发逻辑的场景(如数据校验后直接执行回调)。
// 步骤 1:定义回调类型(可选,但推荐提高可读性)
typedef OnSuccessCallback = void Function(String message); // 成功回调(带 String 参数)
typedef OnErrorCallback = void Function(Exception e); // 错误回调(带 Exception 参数)// 步骤 2:创建一个接受回调的函数(此处模拟一个“数据处理”操作)
void processData(String data, {OnSuccessCallback? onSuccess, OnErrorCallback? onError}) {try {// 模拟数据处理逻辑(例如校验数据长度)if (data.length > 10) {throw Exception("数据过长(最大 10 字符)");}// 数据处理成功,触发成功回调if (onSuccess != null) {onSuccess("数据处理成功,结果:$data"); // 传递结果给回调}} catch (e) {// 数据处理失败,触发错误回调if (onError != null) {onError(e as Exception); // 传递异常给回调}}
}// 步骤 3:注册并使用回调
void main() {// 注册成功和错误回调processData("HelloDart", onSuccess: (result) => print("成功:$result"), // 注册成功回调onError: (e) => print("失败:${e.toString()}"), // 注册错误回调);// 测试错误场景(数据过长)processData("ThisIsAVeryLongString", onSuccess: (result) => print("成功:$result"),onError: (e) => print("失败:${e.toString()}"), // 会触发此回调);
}
输出结果:
成功:数据处理成功,结果:HelloDart
失败:Exception: 数据过长(最大 10 字符)
2、异步回调(延迟执行)
适用于模拟异步操作(如网络请求、文件读写),操作完成后触发回调。
// 步骤 1:定义异步回调类型(带结果参数)
typedef AsyncDataCallback = void Function(String? data, Exception? error);// 步骤 2:创建异步函数(模拟网络请求)
Future<void> fetchDataFromServer(String url, AsyncDataCallback callback) async {try {// 模拟网络延迟(2 秒)await Future.delayed(Duration(seconds: 2));// 模拟成功响应(实际中可能是 HTTP 请求结果)final mockResponse = "服务器返回的数据:$url";callback(mockResponse, null); // 成功时传递数据和 null 错误} catch (e) {callback(null, e as Exception); // 失败时传递 null 数据和异常}
}// 步骤 3:注册并使用异步回调
void main() {print("开始请求数据...");fetchDataFromServer("https://api.example.com/data", (data, error) {if (error != null) {print("请求失败:$error");return;}print("请求成功,数据:$data"); // 2 秒后输出此内容},);print("等待数据返回..."); // 会在请求开始后立即执行(异步非阻塞)
}
输出结果:
开始请求数据...
等待数据返回...
请求成功,数据:服务器返回的数据:https://api.example.com/data
3、事件监听(多回调注册)
适用于需要多个监听器响应同一事件的场景(如按钮点击、自定义事件)。
// 步骤 1:定义事件类型和回调类型
enum EventType { buttonClick, dataLoaded }typedef EventCallback = void Function(EventType type, dynamic payload);// 步骤 2:创建事件管理器(维护回调列表)
class EventManager {final List<EventCallback> _callbacks = [];// 注册回调void onEvent(EventCallback callback) {_callbacks.add(callback);}// 触发事件(调用所有注册的回调)void emitEvent(EventType type, [dynamic payload]) {for (final callback in _callbacks) {callback(type, payload); // 依次调用所有回调}}// 可选:移除回调(避免内存泄漏)void removeCallback(EventCallback callback) {_callbacks.remove(callback);}
}// 步骤 3:使用事件管理器注册和触发回调
void main() {final eventManager = EventManager();// 注册第一个回调(监听按钮点击)eventManager.onEvent((type, payload) {if (type == EventType.buttonClick) {print("按钮被点击,位置:${payload['x']}, ${payload['y']}");}});// 注册第二个回调(监听数据加载)eventManager.onEvent((type, payload) {if (type == EventType.dataLoaded) {print("数据加载完成,数据量:${payload.length} 条");}});// 模拟触发事件(例如用户点击按钮)eventManager.emitEvent(EventType.buttonClick, {'x': 100, 'y': 200});// 模拟触发事件(例如数据加载完成)eventManager.emitEvent(EventType.dataLoaded, ['数据1', '数据2', '数据3']);
}
输出结果:
按钮被点击,位置:100, 200
数据加载完成,数据量:3 条
关键总结
回调类型定义:推荐使用 typedef 明确回调的参数和返回值类型,提高代码可读性。
同步 vs 异步:同步回调立即执行(如数据处理),异步回调通过 Future 或 Stream 实现(如网络请求)。
多回调管理:通过列表维护多个回调(如事件监听),支持灵活扩展。
内存管理:若回调绑定到生命周期较短的对象(如页面),需及时移除回调避免内存泄漏(如 removeCallback 方法)。