Flutter调用dependOnInheritedWidgetOfExactType返回null的问题排查与解决
Flutter InheritedWidget查找返回null问题排查
问题描述
我尝试使用InheritedWidget方案沿Widget树向下共享状态,为此开发了一个简易计数器应用,可对计数器执行加、减、乘、除任意操作。这是小型演示项目,未遵循开发最佳实践。
代码行context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()不知为何返回null,对照示例和官方文档,该方法应该能在Widget树中定位到MyInheritedWidget并返回实例,但Flutter工具一直提示该值为null,断言校验也确认该值确实为null。
请问该方法返回失败的原因是什么?需要如何调整才能正确获取到MyInheritedWidget实例?
问题代码
文件:main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: Counter(), ); } } class Counter extends StatefulWidget { const Counter({Key? key}) : super(key: key); @override CounterState createState() => CounterState(); } class CounterState extends State<Counter> { int counter = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Counter App'), centerTitle: true, ), body: MyInheritedWidget( counterState: this, child: Builder( builder: (BuildContext innerContext) { return CounterViewer( counterState: MyInheritedWidget.of(context).counterState); }, ), ), ); } void addCounter(int value) { setState(() { counter++; }); } void subtractCounter(int value) { setState(() { counter--; }); } void multiplyCounter(int value) { setState(() { counter *= value; }); } void divideCounter(int value) { setState(() { counter = (counter / value).toInt(); }); } } class MyInheritedWidget extends InheritedWidget { final CounterState counterState; const MyInheritedWidget( {Key? key, required Widget child, required this.counterState}) : super(key: key, child: child); static MyInheritedWidget of(BuildContext context) { final MyInheritedWidget? widget = context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>(); assert(widget != null); return widget!; } @override bool updateShouldNotify(covariant InheritedWidget oldWidget) { return true; } } class CounterViewer extends StatelessWidget { final CounterState counterState; const CounterViewer({Key? key, required this.counterState}) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ Container( color: Colors.green.shade200, width: MediaQuery.of(context).size.width, height: 180, child: Center( child: Text( '220', style: TextStyle( color: Colors.grey.shade50, fontSize: 60, fontWeight: FontWeight.bold, ), ), ), ), Container( color: Colors.grey.shade300, padding: EdgeInsets.symmetric(vertical: 16), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () {}, child: Text('Add'), ), ElevatedButton( onPressed: () {}, child: Text('Subtract'), ), ElevatedButton( onPressed: () {}, child: Text('Multiply'), ), ElevatedButton( onPressed: () {}, child: Text('Divide'), ), ], ), ) ], ); } }
原因与解决方案
根本原因
dependOnInheritedWidgetOfExactType方法是从传入的context对应的Widget节点开始,向上遍历父节点查找指定类型的InheritedWidget。问题代码里调用MyInheritedWidget.of(context)时传入的是CounterState的build方法入参context,这个context对应的节点在MyInheritedWidget的上层,向上自然找不到对应的InheritedWidget实例,所以返回null。
修复方案
将of方法的入参替换为Builder构造器提供的innerContext,这个context对应的节点是MyInheritedWidget的子节点,向上遍历就能找到目标实例。修复后的代码如下:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Counter App'), centerTitle: true, ), body: MyInheritedWidget( counterState: this, child: Builder( builder: (BuildContext innerContext) { return CounterViewer( counterState: MyInheritedWidget.of(innerContext).counterState); }, ), ), ); }
内容的提问来源于stack exchange,提问作者Ariel
相关产品推荐
相关产品推荐

