Error: Could not find the correct Provider< > above this Widget
Error: Could not find the correct Provider< > above this Widget
我看不出我在下面做错了什么,但它抛出了一些提供程序错误和构建上下文:
发生这种情况是因为您使用了不包含提供商的 BuildContext
你的选择。有几个常见的场景:
您在 main.dart
中添加了一个新提供程序并执行了热重载。
要修复,请执行热重启。
您尝试读取的提供商在不同的路径上。
提供商是“范围内的”。因此,如果您在路由中插入提供者,则
其他路由将无法访问该提供商。
您使用的 BuildContext
是您尝试读取的提供商的祖先。
确保 SubscriptionsPage 在您的 MultiProvider/Provider 下。
这通常发生在您创建提供程序并尝试立即读取它时。
例如,而不是:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
考虑像这样使用 builder
:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
class RevenueCatProvider extends ChangeNotifier{
RevenueCatProvider() {
init();
}
Entitlement _entitlement = Entitlement.free;
Entitlement get entitlement => _entitlement;
Future init() async {
Purchases.addPurchaserInfoUpdateListener((purchaserInfo) async {
updatePurchasesStatus();
});
}
Future updatePurchasesStatus() async {
final purchaserInfo = await Purchases.getPurchaserInfo();
final entitlements = purchaserInfo.entitlements.active.values.toList();
_entitlement = entitlements.isEmpty ? Entitlement.free : Entitlement.pro;
notifyListeners();
}
}
class SubscriptionsPage extends StatefulWidget {
const SubscriptionsPage({Key? key}) : super(key: key);
@override
State<SubscriptionsPage> createState() => _SubscriptionsPageState();
}
class _SubscriptionsPageState extends State<SubscriptionsPage> {
bool isLoading = false;
@override
Widget build(BuildContext context) {
final entitlement = Provider.of<RevenueCatProvider>(context).entitlement;
return Scaffold(
appBar: AppBar(
title: const Text('Subscription Page'),
),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buildEntitlement(entitlement),
const SizedBox(height: 32),
Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(50),
),
child: const Text(
'See Available Plans',
style: TextStyle(fontSize: 20),
),
onPressed: () => isLoading ? null : fetchOffers,
),
),
const SizedBox(height: 32),
SizedBox(
height: 200,
child: Image.asset('images/logo_transparent.png'),
),
],
),
),
);
}
Widget buildEntitlement(Entitlement entitlement) {
switch (entitlement) {
case Entitlement.pro:
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
SizedBox(height: 40),
Text('You are on a Paid plan',
style: TextStyle(
fontSize: 20,
),
),
SizedBox(height: 10),
Icon(Icons.paid,
size: 100,
),
],
);
case Entitlement.free:
default:
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
SizedBox(height: 40),
Text('You are on a Free plan',
style: TextStyle(
fontSize: 20,
),
),
SizedBox(height: 10),
Icon(Icons.lock,
size: 100,
),
],
);
}
}
Future fetchOffers() async {
final offerings = await PurchaseApi.fetchOffers();
if (offerings.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('No Subscription'),
));
} else {
final packages = offerings
.map((offer) => offer.availablePackages)
.expand((pair) => pair)
.toList();
showModalBottomSheet(
useRootNavigator: true,
isDismissible: true,
isScrollControlled: true,
backgroundColor: kLightPrimary,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setModalState) {
return PaywallWidget(
packages: packages,
title: '⭐️ Upgrade your plan',
description: 'Upgrade your plan to enjoy unlimited ad-free reviews',
onClickedPackage: (package) async {
await PurchaseApi.purchasePackage(package);
Navigator.pop(context);
},
);
});
},
);
}
}
}
您需要确保在使用更改通知程序的小部件上方的小部件树中某处有一个 ChangeNotifierProvider
。
例如,当您调用 final entitlement = Provider.of<RevenueCatProvider>(context).entitlement;
时。遍历小部件树以搜索匹配的 ChangeNotifierProvider
.
您收到的错误告诉您,有 none。
像这样的东西应该有用。
class Sample extends StatelessWidget {
const Sample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => new RevenueCatProvider(),
child: SubscriptionsPage(),
);
}
}
我看不出我在下面做错了什么,但它抛出了一些提供程序错误和构建上下文:
发生这种情况是因为您使用了不包含提供商的 BuildContext
你的选择。有几个常见的场景:
您在
main.dart
中添加了一个新提供程序并执行了热重载。 要修复,请执行热重启。您尝试读取的提供商在不同的路径上。
提供商是“范围内的”。因此,如果您在路由中插入提供者,则 其他路由将无法访问该提供商。
您使用的
BuildContext
是您尝试读取的提供商的祖先。确保 SubscriptionsPage 在您的 MultiProvider/Provider 下。 这通常发生在您创建提供程序并尝试立即读取它时。
例如,而不是:
Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // Will throw a ProviderNotFoundError, because `context` is associated // to the widget that is the parent of `Provider<Example>` child: Text(context.watch<Example>()), ), }
考虑像这样使用
builder
:Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // we use `builder` to obtain a new `BuildContext` that has access to the provider builder: (context) { // No longer throws return Text(context.watch<Example>()), } ), }
class RevenueCatProvider extends ChangeNotifier{
RevenueCatProvider() {
init();
}
Entitlement _entitlement = Entitlement.free;
Entitlement get entitlement => _entitlement;
Future init() async {
Purchases.addPurchaserInfoUpdateListener((purchaserInfo) async {
updatePurchasesStatus();
});
}
Future updatePurchasesStatus() async {
final purchaserInfo = await Purchases.getPurchaserInfo();
final entitlements = purchaserInfo.entitlements.active.values.toList();
_entitlement = entitlements.isEmpty ? Entitlement.free : Entitlement.pro;
notifyListeners();
}
}
class SubscriptionsPage extends StatefulWidget {
const SubscriptionsPage({Key? key}) : super(key: key);
@override
State<SubscriptionsPage> createState() => _SubscriptionsPageState();
}
class _SubscriptionsPageState extends State<SubscriptionsPage> {
bool isLoading = false;
@override
Widget build(BuildContext context) {
final entitlement = Provider.of<RevenueCatProvider>(context).entitlement;
return Scaffold(
appBar: AppBar(
title: const Text('Subscription Page'),
),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buildEntitlement(entitlement),
const SizedBox(height: 32),
Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(50),
),
child: const Text(
'See Available Plans',
style: TextStyle(fontSize: 20),
),
onPressed: () => isLoading ? null : fetchOffers,
),
),
const SizedBox(height: 32),
SizedBox(
height: 200,
child: Image.asset('images/logo_transparent.png'),
),
],
),
),
);
}
Widget buildEntitlement(Entitlement entitlement) {
switch (entitlement) {
case Entitlement.pro:
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
SizedBox(height: 40),
Text('You are on a Paid plan',
style: TextStyle(
fontSize: 20,
),
),
SizedBox(height: 10),
Icon(Icons.paid,
size: 100,
),
],
);
case Entitlement.free:
default:
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
SizedBox(height: 40),
Text('You are on a Free plan',
style: TextStyle(
fontSize: 20,
),
),
SizedBox(height: 10),
Icon(Icons.lock,
size: 100,
),
],
);
}
}
Future fetchOffers() async {
final offerings = await PurchaseApi.fetchOffers();
if (offerings.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('No Subscription'),
));
} else {
final packages = offerings
.map((offer) => offer.availablePackages)
.expand((pair) => pair)
.toList();
showModalBottomSheet(
useRootNavigator: true,
isDismissible: true,
isScrollControlled: true,
backgroundColor: kLightPrimary,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setModalState) {
return PaywallWidget(
packages: packages,
title: '⭐️ Upgrade your plan',
description: 'Upgrade your plan to enjoy unlimited ad-free reviews',
onClickedPackage: (package) async {
await PurchaseApi.purchasePackage(package);
Navigator.pop(context);
},
);
});
},
);
}
}
}
您需要确保在使用更改通知程序的小部件上方的小部件树中某处有一个 ChangeNotifierProvider
。
例如,当您调用 final entitlement = Provider.of<RevenueCatProvider>(context).entitlement;
时。遍历小部件树以搜索匹配的 ChangeNotifierProvider
.
您收到的错误告诉您,有 none。
像这样的东西应该有用。
class Sample extends StatelessWidget {
const Sample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => new RevenueCatProvider(),
child: SubscriptionsPage(),
);
}
}