在颤振中使用提供者时,getter 被调用为 null

Posted

技术标签:

【中文标题】在颤振中使用提供者时,getter 被调用为 null【英文标题】:getter was called on null when using provider in flutter 【发布时间】:2020-06-06 11:39:08 【问题描述】:

我正在使用提供者模式制作一个颤振应用程序。 当我启动我的应用程序时,我收到了 null 错误。

button_data.dart 是这样的。

class ButtonData extends ChangeNotifier 
  List<Button> _buttons = [
    Button(
        type: "A",
        numberone: "1",
        numbertwo: "2",
        numberthree: "3",
    ),
    Button(
        key: "B",
        numberone: "A",
        numbertwo: "B",
        numberthree: "C",
    ),
  ];

  Button _selectedButton;

  List<Button> get buttons => _buttons;

  Button get selectedButton => _selectedButton;

  void setSelectedItem(Button s) 
    _selectedButton = s;
    notifyListeners();
  


 Button getType(String value) 
    return _buttons
        .where((button) => button.type == value).first;
   // it is no use...

当我切换类型时,我希望这些按钮以不同的方式显示。

new Row(children: [
  buildButton(Provider.of<ButtonData>(context).getNumberOne(Provider.of<ButtonData>(context).selectedButton.type)),
  buildButton(Provider.of<ButtonData>(context).getNumberTwo(Provider.of<ButtonData>(context).selectedButton.type)),
  buildButton(Provider.of<ButtonData>(context).getNumberThree(Provider.of<ButtonData>(context).selectedButton.type)),
])

但似乎返回了错误,因为我可能没有设置默认值。 它说'getter'type'在null上被调用' 如果可能,我希望将“type A”设置为默认值,以便在按钮上显示 1、2、3。

所以,要找出空错误, 我尝试了下面的initState 函数,但这会引发更多错误。

1. There isn't a setter named 'selectedButton' in class 'ButtonData'

2. The expression here has a type of void and therefore can't be used

@override
void initState() 
  Provider.of<ButtonData>(context).selectedButton = Provider.of<ButtonData>(context).setSelectedItem(Provider.of<ButtonData>(context).buttons.first);
  super.initState();

我一直在寻找类似的问题,但找不到确切的问题,所以我问你们。

【问题讨论】:

【参考方案1】:

你在这里做错了很多事情。您需要了解 Provider 可以暴露给它下面的所有 Widget。此外,这也将有助于其他人更多地了解FlutterProvider

首先,请确保您从要使用该值的 Row 上方的某个位置公开 ButtonData 对象。

像这样:

//You can use this in the build method, and wrap it on top of your page Scaffold. 

//@override
//Widget build(BuildContext context) 
return ChangeNotifierProvider(
        create: (_) => ButtonData(),
        child: Scaffold(
          appBar: _appBar(),
          body: _body(),
        ),
      );
//

第二,您在Row 小部件中获取按钮的方式非常糟糕,当您想在代码中多次使用您的对象时,您应该使用Consumer 小部件将您的 ButtonData 公开为变量并使用它而不是整行:Provider.of&lt;ButtonData&gt;(context)

看看这个:

//WRONG WAY
new Row(children: [
  buildButton(Provider.of<ButtonData>(context).getNumberOne(Provider.of<ButtonData>(context).selectedButton.type)),
  buildButton(Provider.of<ButtonData>(context).getNumberTwo(Provider.of<ButtonData>(context).selectedButton.type)),
  buildButton(Provider.of<ButtonData>(context).getNumberThree(Provider.of<ButtonData>(context).selectedButton.type)),
])

//CORRECT WAY
Consumer<ButtonData>(
  builder: (BuildContext context, ButtonData buttonData, Widget child) => Row(
    children: <Widget>[
      buildButton(buttonData.getNumberOne(buttonData.selectedButton.type)),
      buildButton(buttonData.getNumberTwo(buttonData.selectedButton.type)),
      buildButton(buttonData.getNumberThree(buttonData.selectedButton.type)),
    ],
  ),
);

此外,如果您在 initState 函数中获取 Provider 值,这意味着您正在获取小部件树之外的值。 (无论您在 build 函数中返回的内容都是您的小部件树)。要获取小部件树之外的值,请使用它。

///WRONG
Provider.of<ButtonData>(context).selectedButton = Provider.of<ButtonData>(context).setSelectedItem(Provider.of<ButtonData>(context).buttons.first);

///CORRECT
///You need to set `listen` to false.
Provider.of<ButtonData>(context, listen: false).selectedButton = Provider.of<ButtonData>(context, listen: false).setSelectedItem(Provider.of<ButtonData>(context, listen: false).buttons.first);

///BETTER
ButtonData buttonData = Provider.of<ButtonData>(context, listen: false);
buttonData.selectedButton = buttonData.setSelectedItem(buttonData.buttons.first);

还有一个提示... 您不需要使用new 关键字,如果您在教程中看到过,那是因为那些教程很老,并且使用的是 Dart 1,目前在 Dart 2 中,不再需要 new 关键字.

希望这会有所帮助!

更新:

您的ButtonData 类中也缺少声明。

对你在评论中提到的错误的解释:

//If you want to use the following:
Provider.of<ButtonData>(context, listen: false).selectedButton = xyz;

//You need to declare a setter named `selectedButton` in your ButtonData
// class. Like so:

set selectedButton(Button button) 
    _selectedButton = button;
    notifyListeners();


//Currently, in your ButtonData class, you have not declared a setter,
// instead you created a method there for updating the value. 
//This one.

void setSelectedItem(Button s) 
    _selectedButton = s;
    notifyListeners();


//If you want to use this method for updating your `selectedButton` value,
// you can use the following line of code.
Provider.of<ButtonData>(context, listen: false).setSelectedItem(xyz);

【讨论】:

谢谢,BasedMusa!我多次编码该对象的原因是我使用多提供者并且我使用其他对象作为消费者,所以我不知道如何使用多消费者方式......但我真的很感激......现在我知道我的问题是什么代码。 我只是尝试按照您建议的方式获取我的 Provider 值。但错误返回。 1. 'ButtonData' 类中没有名为 'selectedButton' 的 setter 2. 这里的表达式是 void 类型,因此不能使用 - @***lynLee 你可以检查更新的区块,我解释了问题是什么以及如何解决它们。 谢谢。我只是接受并投了票。二传手似乎工作。但是当我使用 initstate.. 时我仍然遇到另一个错误 :-( 我有同样的问题,我在这里创建了一个问题。你能帮我吗。 ***.com/q/65419586/5901713【参考方案2】:

在大多数情况下,您只需使用 Statefull.mounted 属性即可修复它。

initState() 
  if (mounted) 
    context.read<YouType>();
  

  super.initState();

【讨论】:

以上是关于在颤振中使用提供者时,getter 被调用为 null的主要内容,如果未能解决你的问题,请参考以下文章

颤振构建运行器不起作用 - 调用了 getter 'uri' 为 null

吸气剂'loadingStatus'在空颤时被调用

升级颤振后颤振标签栏错误“getter'key'被称为null”

Jersey JAX-RS REST“getter”方法总是被调用

颤振错误“方法'toLowerCase()'在null上被调用”

在 null 上调用了方法“timeZone”。 (颤振)[重复]