getter 在 flutter 中使用 provider 时调用 null
getter was called on null when using provider in flutter
我正在使用提供者模式制作一个 flutter 应用程序。
当我启动我的应用程序时出现空错误。
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' 被调用为空”
如果可能的话,我希望将 '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();
}
我一直在寻找类似的问题,但我找不到确切的问题,所以我问你们。
你这里有很多地方做错了。你需要明白 Provider 是可以暴露给它下面的所有 Widget 的。此外,这也将帮助其他人更多地了解 Flutter
和 Provider
。
首先,确保从要使用该值的行上方的某处公开 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<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)),
],
),
);
此外,如果您在 initState
函数中获取 Provider
值,这意味着您正在获取小部件树外部的值。 (无论你在 build
函数中 return 是你的小部件树)。要获取小部件树之外的值,请使用它。
///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
class.
中也缺少声明
您在评论中提到的错误的解释:
//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);
对于大多数情况,您可以使用 Statefull.mounted
属性.
来修复它
initState() {
if (mounted) {
context.read<YouType>();
}
super.initState();
}
我正在使用提供者模式制作一个 flutter 应用程序。 当我启动我的应用程序时出现空错误。
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' 被调用为空” 如果可能的话,我希望将 '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();
}
我一直在寻找类似的问题,但我找不到确切的问题,所以我问你们。
你这里有很多地方做错了。你需要明白 Provider 是可以暴露给它下面的所有 Widget 的。此外,这也将帮助其他人更多地了解 Flutter
和 Provider
。
首先,确保从要使用该值的行上方的某处公开 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<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)),
],
),
);
此外,如果您在 initState
函数中获取 Provider
值,这意味着您正在获取小部件树外部的值。 (无论你在 build
函数中 return 是你的小部件树)。要获取小部件树之外的值,请使用它。
///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
class.
您在评论中提到的错误的解释:
//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);
对于大多数情况,您可以使用 Statefull.mounted
属性.
initState() {
if (mounted) {
context.read<YouType>();
}
super.initState();
}