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

Bro*_*Lee 3 provider dart flutter flutter-provider

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

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...
}
Run Code Online (Sandbox Code Playgroud)

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

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)),
])
Run Code Online (Sandbox Code Playgroud)

但错误似乎得到了返回,因为也许我没有设置默认值。它说'getter 'type' was called on 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();
}
Run Code Online (Sandbox Code Playgroud)

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

Bas*_*usa 8

你在这里做错了很多事情。您需要了解 Provider 可以向其下方的所有 Widget 公开。此外,这也将有助于其他人理解FlutterProvider多一点。

首先,确保从要使用该值的行上方的某处公开 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(),
        ),
      );
//}

Run Code Online (Sandbox Code Playgroud)


其次,您用来在Row小部件中获取按钮的方式非常糟糕,当您想在代码中多次使用您的对象时,您应该使用Consumer小部件将您的 ButtonData 作为变量公开并使用它而不是整个线:Provider.of<ButtonData>(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)),
    ],
  ),
);
Run Code Online (Sandbox Code Playgroud)

此外,如果您ProviderinitState函数中获取值,则意味着您正在获取小部件树之外的值。(无论您在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);
Run Code Online (Sandbox Code Playgroud)

还有一个提示... 你不需要使用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);

Run Code Online (Sandbox Code Playgroud)