错误无法在此小部件上方找到正确的提供者
Error could not find the correct provider above this widget
好的,我在使用 FutureProvider 时遇到了这个问题。
我已经在我的 MaterialApp 上面创建了一个 FutureProvider,所以它应该被识别了吧?
我的小部件树有点像这样:
MyApp >> Home >> CardVehicle
这是我的 main.dart 代码,我在其中创建对象 Provider:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final Service service = Service();
@override
Widget build(BuildContext context) {
return FutureProvider(
create: (_) => service.fetchCarYear(),
catchError: (_, error) => print(error),
child: MaterialApp(
title: 'KPM Demo',
theme: ThemeData(
primarySwatch: Colors.amber,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Home(),
),
);
}
}
我的虚拟服务class:
class Service {
Future<CarYear> fetchCarYear() async {
CarYear carYear = CarYear();
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
carYear = CarYear.fromJson(jsonDecode(response));
return carYear;
}
}
这里是我放置 Provider 的地方:
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
CarYear carYear = Provider.of<CarYear>(context);
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year)))
.toList() ?? null,
onChanged: null,
),
],
),
);
}
}
我是不是哪里弄错了?请帮忙!
编辑:这是我的 CarYear class:
class CarYear {
List<Data> data;
CarYear({this.data});
CarYear.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = new List<Data>();
json['data'].forEach((v) {
data.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
String year;
Data({this.year});
Data.fromJson(Map<String, dynamic> json) {
year = json['year'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['year'] = this.year;
return data;
}
}
最好使用 ChangeNotifierProvider
在您使用 MultiProvider 创建的主体中
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => Service()),
],
child: MaterialApp(..)
)
}
在服务中 class 我添加了 extends ChangeNotifiere
当 notifyListeners()
调用时,所有消费者都会更新
class Service extends ChangeNotifier {
// Variable set in Service
CarYear _carYear = new CarYear();
CarYear get carYear => _carYear;
// init MultiProvider create() =>
Service() {
fetchCarYear();
}
Future<CarYear> fetchCarYear() async {
_carYear = CarYear();
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
// update _carYear Variable
_carYear = CarYear.fromJson(jsonDecode(response));
// all Consumer get a refresh()
notifyListeners();
}
}
在 CardVehicle 中我放置了一个 Consumer 但 CarYear carYear = Provider.of<Service>(context).carYear
也在工作..
但是使用 Provider.of 你每 notifyListeners()
更新整个小部件
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
// its better you do it here with a Consumer, because not the whole widget is updating
new Consumer<Service>(
builder: (context, service, child) => new DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: service.carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
.toList(),
onChanged: (value) {
print(value);
},
),
),
],
),
);
}
}
您需要将 futureProvider
的 catchError
更改为 return a CarYear 而不是 void。现在 futureProvider
是 Dynamic 类型,provider.of
搜索的不是 dynamic 的提供者,而是 CarYear[=27= 的提供者].
为避免这种情况,请将 catchError
return 设置为空的 CarYear 或使其抛出异常。
希望对您有所帮助!
仅使用 FutureProvider 的示例
MultiProvider(
providers: [
FutureProvider(create: (_) => Service().fetchCarYear()),
],
child: MaterialApp(..)
服务 Class return CarYear
class Service {
// Variable set in Service
CarYear _carYear;
Future<CarYear> fetchCarYear() async {
_carYear = CarYear(data: new List());
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
// update _carYear Variable
_carYear = CarYear.fromJson(jsonDecode(response));
// all Consumer get a refresh()
//notifyListeners();
return _carYear;
}
}
和带有 CarYear carYear = Provider.of<CarYear>(context);
的 CardVehicle
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
CarYear carYear = Provider.of<CarYear>(context);
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
new DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: carYear != null ? carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
.toList() : null,
onChanged: (value) {
print(value);
},
),
],
),
);
}
}
好的,我在使用 FutureProvider 时遇到了这个问题。
我已经在我的 MaterialApp 上面创建了一个 FutureProvider,所以它应该被识别了吧?
我的小部件树有点像这样:
MyApp >> Home >> CardVehicle
这是我的 main.dart 代码,我在其中创建对象 Provider:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final Service service = Service();
@override
Widget build(BuildContext context) {
return FutureProvider(
create: (_) => service.fetchCarYear(),
catchError: (_, error) => print(error),
child: MaterialApp(
title: 'KPM Demo',
theme: ThemeData(
primarySwatch: Colors.amber,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Home(),
),
);
}
}
我的虚拟服务class:
class Service {
Future<CarYear> fetchCarYear() async {
CarYear carYear = CarYear();
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
carYear = CarYear.fromJson(jsonDecode(response));
return carYear;
}
}
这里是我放置 Provider 的地方:
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
CarYear carYear = Provider.of<CarYear>(context);
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year)))
.toList() ?? null,
onChanged: null,
),
],
),
);
}
}
我是不是哪里弄错了?请帮忙!
编辑:这是我的 CarYear class:
class CarYear {
List<Data> data;
CarYear({this.data});
CarYear.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
data = new List<Data>();
json['data'].forEach((v) {
data.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
String year;
Data({this.year});
Data.fromJson(Map<String, dynamic> json) {
year = json['year'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['year'] = this.year;
return data;
}
}
最好使用 ChangeNotifierProvider
在您使用 MultiProvider 创建的主体中
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => Service()),
],
child: MaterialApp(..)
)
}
在服务中 class 我添加了 extends ChangeNotifiere
当 notifyListeners()
调用时,所有消费者都会更新
class Service extends ChangeNotifier {
// Variable set in Service
CarYear _carYear = new CarYear();
CarYear get carYear => _carYear;
// init MultiProvider create() =>
Service() {
fetchCarYear();
}
Future<CarYear> fetchCarYear() async {
_carYear = CarYear();
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
// update _carYear Variable
_carYear = CarYear.fromJson(jsonDecode(response));
// all Consumer get a refresh()
notifyListeners();
}
}
在 CardVehicle 中我放置了一个 Consumer 但 CarYear carYear = Provider.of<Service>(context).carYear
也在工作..
但是使用 Provider.of 你每 notifyListeners()
更新整个小部件
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
// its better you do it here with a Consumer, because not the whole widget is updating
new Consumer<Service>(
builder: (context, service, child) => new DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: service.carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
.toList(),
onChanged: (value) {
print(value);
},
),
),
],
),
);
}
}
您需要将 futureProvider
的 catchError
更改为 return a CarYear 而不是 void。现在 futureProvider
是 Dynamic 类型,provider.of
搜索的不是 dynamic 的提供者,而是 CarYear[=27= 的提供者].
为避免这种情况,请将 catchError
return 设置为空的 CarYear 或使其抛出异常。
希望对您有所帮助!
仅使用 FutureProvider 的示例
MultiProvider(
providers: [
FutureProvider(create: (_) => Service().fetchCarYear()),
],
child: MaterialApp(..)
服务 Class return CarYear
class Service {
// Variable set in Service
CarYear _carYear;
Future<CarYear> fetchCarYear() async {
_carYear = CarYear(data: new List());
final response = await Future.delayed(
Duration(milliseconds: 500),
() => jsonEncode({
"data": [
{"year": "2020"},
{"year": "2019"},
{"year": "2018"}
]
}),
);
// update _carYear Variable
_carYear = CarYear.fromJson(jsonDecode(response));
// all Consumer get a refresh()
//notifyListeners();
return _carYear;
}
}
和带有 CarYear carYear = Provider.of<CarYear>(context);
class CardVehicle extends StatelessWidget {
@override
Widget build(BuildContext context) {
CarYear carYear = Provider.of<CarYear>(context);
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Column(
children: <Widget>[
new DropdownButton(
isExpanded: true,
icon: Icon(Icons.keyboard_arrow_down),
items: carYear != null ? carYear.data
.map((item) => DropdownMenuItem(child: Text(item.year), value: item.year,))
.toList() : null,
onChanged: (value) {
print(value);
},
),
],
),
);
}
}