Flutter FutureBuilder异常如何添加通用默认处理行为?
异常无法捕获的原因
FutureBuilder内部已经实现了对传入Future的异常捕获逻辑,所有异常会被封装到AsyncSnapshot.error属性中,不会向上抛到Flutter框架层或者Zone环境,因此你配置的全局异常捕获回调无法接收到这部分异常。
低冗余解决方案:封装通用自定义FutureBuilder
直接封装一层自定义的FutureBuilder组件,内置默认的加载态、错误处理、异常上报逻辑,业务层直接调用封装后的组件即可,无需每个页面重复写判断逻辑。
封装代码示例
import 'package:flutter/material.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; typedef AsyncSuccessBuilder<T> = Widget Function( BuildContext context, T data, ); class CommonFutureBuilder<T> extends StatelessWidget { final Future<T> future; final AsyncSuccessBuilder<T> onSuccess; final Widget Function(Object error, StackTrace stackTrace)? onError; final Widget? onLoading; const CommonFutureBuilder({ super.key, required this.future, required this.onSuccess, this.onError, this.onLoading, }); @override Widget build(BuildContext context) { return FutureBuilder<T>( future: future, builder: (context, snapshot) { // 加载状态走全局默认逻辑,支持自定义覆盖 if (snapshot.connectionState == ConnectionState.waiting) { return onLoading ?? const Center(child: CircularProgressIndicator()); } // 错误状态统一上报+全局默认处理,支持自定义覆盖 if (snapshot.hasError) { final error = snapshot.error!; final stackTrace = snapshot.stackTrace!; // 全局统一上报错误到Crashlytics,无需业务层重复处理 FirebaseCrashlytics.instance.recordError(error, stackTrace); return onError?.call(error, stackTrace) ?? _defaultErrorWidget(error); } // 成功状态返回业务自定义内容 return onSuccess(context, snapshot.data as T); }, ); } // 全局通用默认错误视图 Widget _defaultErrorWidget(Object error) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.error_outline, color: Colors.red, size: 48), const SizedBox(height: 16), Text('加载失败:${error.toString()}'), ], ), ); } }
业务层使用方式
无需重复处理加载、错误、上报逻辑,仅在需要自定义特殊样式时额外传参即可:
// 常规场景,直接走全局默认逻辑 CommonFutureBuilder<String>( future: loadServerData(), onSuccess: (context, data) { return Text(data); }, ) // 需要自定义样式的特殊场景,单独传参覆盖默认逻辑 CommonFutureBuilder<String>( future: loadServerData(), onSuccess: (context, data) => Text(data), onError: (error, stackTrace) => CustomErrorPage(error), onLoading: CustomLoadingAnimation(), )
注意:传入的future需要提前在
initState等生命周期中初始化,不要直接在build方法中创建,否则组件每次重绘都会重新触发Future请求。
内容的提问来源于stack exchange,提问作者alexlipa
相关产品推荐
相关产品推荐

