将 Provider 3 转换为 4 后 Flutter 应用程序崩溃

mar*_*cks 14 flutter

我尝试升级我的 Flutter 应用程序以供Provider 4.0.1今天使用,但以下代码在将值分配为 null 时崩溃。

这是我试图转换的代码。我只改SingleChildCloneableWidgetSingleChildStatelessWidget其编译OK。

import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';

List<SingleChildStatelessWidget> providers = [
  ...independentServices,
  ...dependentServices,
  ...uiConsumableProviders
];

List<SingleChildStatelessWidget> independentServices = [
  Provider.value(value: Api()),
  Provider.value(value: Tbl()),
  Provider.value(value: Bill()),
  Provider.value(value: Sale()),
  Provider.value(value: Category()),
  Provider.value(value: Menu()),
];

List<SingleChildStatelessWidget> dependentServices = [
  ProxyProvider<Api, AuthenticationService>(
    update: (context, api, authenticationService) => AuthenticationService(api: api),
  ),
];

List<SingleChildStatelessWidget> uiConsumableProviders = [
  StreamProvider<User>(
    create: (context) => Provider.of<AuthenticationService>(context, listen: false).user,
  ),
    lazy: false
];
Run Code Online (Sandbox Code Playgroud)

我是这样实现的:

StreamController<User> _userController = StreamController<User>();
Stream<User> get user => _userController.stream;
Run Code Online (Sandbox Code Playgroud)

崩溃发生在这一行:

Future<void> _setFixedLanguageStrings(BuildContext context) async {

 User _user = Provider.of<User>(context);
 
 _user.homeString = await translate(context, 'Home');
Run Code Online (Sandbox Code Playgroud)

在 null 上调用了 getter 'language'。接收器:空

这很好用,Provider 3.0.3但显然我需要做更多。

我的原始代码来自 本教程

编辑:我通过添加lazy: false流提供程序创建方法解决了该问题,但随后在此代码中出现了另一个错误。

Future<String> translate(BuildContext context, _term) async {

  final String _languageCode = Provider.of<User>(context).language;
Run Code Online (Sandbox Code Playgroud)

产生了这个错误:

发生异常。_AssertionError ('package:provider/src/provider.dart': Failed assertion: line 213 pos 7: 'context.owner.debugBuilding || listen == false || _debugIsInInheritedProviderUpdate': 试图监听提供者公开的值,来自在小部件树之外。

这可能是由调用 Provider.of 而不传递 的事件处理程序(如按钮的 onPressed)引起的listen: false

要修复,请编写:Provider.of(context, listen: false);

它不受支持,因为当小部件树不关心该值时,可能会毫无意义地重建与事件处理程序关联的小部件。)

我添加listen: false到上面似乎解决了该问题的行,但是我尝试使用的下一个提供程序产生了此错误:

试图从小部件树外部监听提供者公开的值。

这可能是由调用 Provider.of 而不传递 的事件处理程序(如按钮的 onPressed)引起的listen: false

要修复,请编写:Provider.of(context, listen: false);

它不受支持,因为当小部件树不关心该值时,可能会毫无意义地重建与事件处理程序关联的小部件。'package:provider/src/provider.dart':断言失败:第 213 行位置 7:'context.owner.debugBuilding || 听 == 假 || _debugIsInInheritedProviderUpdate'

我现在应该去调用提供者的每个实例并添加listen: false吗?我需要有人解释发生了什么变化以及原因,因为我在 Flutter 还是个新手,而且Provider. 有很多次我在我的代码中调用 Provider 并且最后一个错误没有返回代码位置。

listen: false现在总是在它之前是不是需要或有我错过了什么东西?我开始在每次调用时添加 listen: false 以实例化 Provider 变量,它似乎正在工作,但这是正确的方法吗?我应该添加listen: false到每个电话Provider.of并称之为一天吗?

编辑:每当从窗口小部件树的可见部分之外调用提供程序时,就会出现错误。这种区别很重要。

duk*_*991 8

我有同样的“问题”,如果我在listen: false任何地方添加我调用 Provider 的问题,问题就消失了,但我不知道这是否是正确的解决方案......?


Ama*_*mar 8

onPressedOnTaponLongPressed等事件处理程序上,我们必须使用

Provider.of<T>(context,listen:false)
Run Code Online (Sandbox Code Playgroud)

原因是他们不会监听任何更新更改,而是负责进行更改。

而像 Text 等小部件负责显示......因此需要在每次更改时更新......因此使用

Provider.of<T>(context,listen:true)  //by default is listen:true
Run Code Online (Sandbox Code Playgroud)


小智 7

listen:true成为默认值是合乎逻辑的。

它没有在事件处理程序中指定不合逻辑的内容。listen: false

此外,4.1.0 将以某种方式提供比 Provider.of 更短的替代方案:

context.read<T>() // Provider.of<T>(context, listen: false)
context.watch<T>() // Provider.of<T>(context)
Run Code Online (Sandbox Code Playgroud)