Flutter报错:当前Widget上层无法找到正确的Networkprovider Provider
问题描述
基于Flutter Provider实现网络连通性检测功能时,触发报错:Error: Could not find the correct Provider<Networkprovider> above this Widget。已尝试调整BuildContext传参、修改Provider放置位置保证子组件可获取对应上下文,在welcome.dart中读取res变量值时仍然触发该错误。
该报错通用触发场景
- main.dart中新增Provider后执行热重载,未重新初始化全局状态:该场景执行热重启即可修复
- 待读取的Provider定义在其他路由内部:Provider具备作用域特性,若在某一路由内部插入Provider,其他路由无法访问该Provider
- 使用的BuildContext属于待读取Provider的祖先节点上下文:需确保读取Provider的组件位于MultiProvider/Provider的子树范围内,该情况常发生在创建Provider后立即尝试读取实例的场景
现有实现代码
main.dart
void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ StreamProvider( create: (context) => Networkprovider().networkController.stream, initialData: Networkprovider().initRes), ], child: MaterialApp( theme: ThemeData(), initialRoute: Welcome.id, routes: { Welcome.id: (context) => Welcome(), NavigatorPage.id: (context) => const NavigatorPage(), }, ), ); } }
NetworkProvider.dart
class Networkprovider extends ChangeNotifier { late StreamSubscription<ConnectivityResult> _subscription; late StreamController<ConnectivityResult> _networkController; late ConnectivityResult initRes = ConnectivityResult.none; StreamSubscription<ConnectivityResult> get subscription => _subscription; StreamController<ConnectivityResult> get networkController => _networkController; Networkprovider() { startup(); } void startup() { _networkController = StreamController<ConnectivityResult>(); networkStatusChangeListener(); } void networkStatusChangeListener() async { _networkController.sink.add(await Connectivity().checkConnectivity()); _subscription = Connectivity().onConnectivityChanged.listen((event) { _networkController.sink.add(event); }); } void disposeStreams() { _subscription.cancel(); _networkController.close(); } }
Welcome.dart
class Welcome extends StatelessWidget { static String id = "welcome_screen"; const Welcome({Key? key}) : super(key: key); @override Widget build(BuildContext context) { var res = Provider.of<Networkprovider>(context); return SafeArea( child: Scaffold( backgroundColor: MAIN_BACKGROUND_COLOR, body: SizedBox.expand( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(12.0), child: Row( children: const <Widget>[ Image(image: AssetImage("assets/images/Magnet_logo.png")) ], ), ), const Padding( padding: EdgeInsets.all(20.0), child: Image(image: AssetImage("assets/images/Mannify_logo.png")), ), const Padding( padding: EdgeInsets.all(10.0), child: Spinner(), ), ], ), ), ), ); } }
问题根因
现有代码没有在组件树中注册Networkprovider类型的Provider:MultiProvider中仅注册了StreamProvider,暴露的对象类型是ConnectivityResult(流发射的网络状态值),且代码中多次调用Networkprovider()构造函数生成了多个独立实例,既无法通过上下文读取到Networkprovider类型对象,还会造成流重复监听、内存泄漏问题。
修复步骤
- 调整main.dart中Provider注册逻辑,先全局注册
Networkprovider实例,再基于该单例实例注册流Provider,避免重复创建对象,同时绑定资源释放逻辑:
void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ // 全局注册Networkprovider单例 ChangeNotifierProvider<Networkprovider>( create: (context) => Networkprovider(), dispose: (context, provider) => provider.disposeStreams(), ), // 基于已注册的Networkprovider实例获取流,不重复new对象 StreamProvider<ConnectivityResult>( create: (context) => context.read<Networkprovider>().networkController.stream, initialData: ConnectivityResult.none, ), ], child: MaterialApp( theme: ThemeData(), initialRoute: Welcome.id, routes: { Welcome.id: (context) => Welcome(), NavigatorPage.id: (context) => const NavigatorPage(), }, ), ); } }
- 调整Welcome.dart中读取Provider的类型,和注册的Provider类型对应:如果需要读取
Networkprovider实例,保持Provider.of<Networkprovider>(context)写法即可;如果需要读取实时网络状态,读取ConnectivityResult类型:
@override Widget build(BuildContext context) { // 读取实时网络连通性结果 ConnectivityResult networkStatus = Provider.of<ConnectivityResult>(context); // 原有布局逻辑保持不变 return SafeArea( // ... 省略原有布局代码 ); }
- 代码修改完成后执行热重启,不要使用热重载,确保全局Provider重新初始化。
内容的提问来源于stack exchange,提问作者Sovit Nayak
相关产品推荐
相关产品推荐

