我想在另一个提供程序方法中使用 fetchdata() 并初始化变量。

我是 Flutter 新手,并且坚持这个问题,我有一个页面使用名为 GoogleMapsNotifier 和 ChangeNotifier 的类,当我弹出页面时,我想在该类中处理 Stream(最后一个函数)。
class GoogleMapsNotifier with ChangeNotifier {
final geolocatorService = GeolocatorService();
final placesService = PlacesService();
final markerService = MarkerService();
Position? currentLocation;
List<PlaceSearch> searchResults = [];
StreamController<Place> selectedLocation = BehaviorSubject<Place>();
StreamController<LatLngBounds> bounds = BehaviorSubject<LatLngBounds>();
late Place selectedLocationStatic;
List<Marker> markers = <Marker>[];
GoogleMapsNotifier() {
setCurrentLocation();
}
setCurrentLocation() async {
currentLocation = await geolocatorService.determinePosition();
selectedLocationStatic = Place(
geometry: Geometry(
location: Location(
lat: currentLocation!.latitude, lng: currentLocation!.longitude),
),
name: '',
vicinity: '');
notifyListeners();
}
searchPlaces(String searchTerm) async {
searchResults …Run Code Online (Sandbox Code Playgroud) 我正在尝试在课堂上创建一个多提供者。但它的工作方式与在 Material 应用程序上方的 main.dart 中声明多重提供程序不同。
class Chat extends StatelessWidget {
const Chat({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<ChatProvider>( create: (context) => ChatProvider()),
ChangeNotifierProvider<MessageProvider>( create: (context) => MessageProvider()),
],
child: ChatMainScreen(),
// MaterialApp(
// debugShowCheckedModeBanner: false,
// home: ChatMainScreen(),
// )
);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在从 ChatMainScreen 导航到另一个屏幕到出现此问题的新屏幕(ChatRoom)。(ChatMainScreen => ChatRoom)
如果我用另一个材质应用程序包装我的 ChatMainScreen ,它似乎可以工作。但是在一个材料应用程序中再有另一个材料应用程序可以吗?
此外,材质应用程序父级到 ChatMainScreen 的路由返回无法正常工作。如果我从 ChatRoom 屏幕按后退按钮,它不会弹出回 chatMainScreen,而是弹出到我推送到 ChatMainScreen 的屏幕上
我是第一次尝试 Flutter,对课程有点困惑MultiProvider。
问题很简单,但我没有找到解释:
应该什么时候使用
Consumer以及什么时候使用context.watch?
例如,以我发现的示例应用程序之一为例,我尝试使用两个提供程序来表示两个全局状态、应用程序的主题和状态:
runApp(
MultiProvider(providers: [
ChangeNotifierProvider(create: (context) => AppTheme()),
ChangeNotifierProvider(create: (context) => AppStatus()),
],
child: const MyApp()
));
Run Code Online (Sandbox Code Playgroud)
然后应用程序小部件通过以下方式访问主题Consumer:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<AppTheme>(
builder: (context, appTheme, child) {
// ...
Run Code Online (Sandbox Code Playgroud)
据我了解,现在所有子小部件都将继承提供程序。这样对吗?
那么,我的主页被MyApp类调用时不使用Consumer,而是context.watch:
@override
Widget build(BuildContext context) {
final appTheme = context.watch<AppTheme>();
final appStatus = context.watch<AppStatus>();
return NavigationView( …Run Code Online (Sandbox Code Playgroud) 这是我的用例:
数据已下载
final dataProvider = FutureProvider<MyModel>((ref) async {
return fetchData();
});
Run Code Online (Sandbox Code Playgroud)
它在小部件的构建方法中像这样使用:
ref.watch(dataProvider).when(
data: DataWidget(data),
error: ErrorWidget(),
loading: LoadingWidget())
Run Code Online (Sandbox Code Playgroud)
用户可以选择刷新数据:
ref.refresh(dataProvider.future);
Run Code Online (Sandbox Code Playgroud)
但是,当出现错误时(例如手机处于飞行模式),会提供错误,因此 DataWidget 会丢失并替换为 ErrorWidget...有没有办法使用 Riverpod 来提供/保留现有数据而不是错误?我相信这是常见的情况,但我没有找到解决这个问题的任何优雅的解决方案。我也阅读了文档,但没有找到与此相关的任何有用信息。我错过了什么吗?(我是 Riverpod 的新手)谢谢
我有一个类需要访问MaterialApp context,但它也需要从所有路由进行全局访问。
要创建全局提供程序,我可以用 包装MaterialApp,Provider但此类提供程序无法访问context. 因此,我必须提供之后的课程MaterialApp。
我意识到我可以用提供者包装每条路由,因为它是无状态的,但我想知道是否有更好的方法来做到这一点。
提前致谢!
void main() {
MainStream.init();
runApp(
MultiProvider(
providers: [
Provider(
create: (context) => Test(context),
),
],
child: MyApp()));
}
class Test {
Test(BuildContext context) {
print("Test");
}
}
Run Code Online (Sandbox Code Playgroud)
在这个测试代码中,我希望在我的应用程序启动时打印出“Test”,但它没有。我做错了什么?我看到了像这样初始化提供程序的示例。
我正在尝试将服务实例(已在同一树级别中创建)注入另一个提供程序。但是在访问提供程序时,我得到了ProviderNotFoundException异常。在下面的代码中NotificationService依赖于AuthService. 这需要在构造函数中传递。因此,我使用Consumer和Provider.value文档中提到的注入它:https : //pub.dev/documentation/provider/latest/provider/Consumer-class.html
这是伪代码:
return MultiProvider(
providers: [
Provider<AuthService>(
create: (ctx) => AuthService(_storage),
dispose: (ctx, v) => v.dispose(),
),
Consumer<AuthService>(
builder: (context, v, child) {
return Provider.value(
value: Provider<NotificationService>(
create: (ctx) => NotificationService(v),
dispose: (ctx, v) => v.dispose(),
),
child: child
);
},
)
],
child: MyApp()
);
Run Code Online (Sandbox Code Playgroud)
在树线的某处,当尝试访问NotificationService实例时,我得到ProviderNotFoundException:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final NotificationService _ns = Provider.of<NotificationService>(context); …Run Code Online (Sandbox Code Playgroud) 假设我想通过使用 a 上的initialValue:属性来初始化一个文本字段TextFormField,并且我需要我的初始值来自提供者。我在文档中读到read()从 build 方法内部调用被认为是不好的做法,但从处理程序调用很好(如onPressed)。所以我想知道从initialValue属性中调用 read 是否可以,如下所示?
我遵循了这个 优秀的Riverpod 教程。在最后的步骤中,作者使用了以下代码:
\nfinal _buttonState = Provider<ButtonState>((ref) {\n return ref.watch(timerProvider.state).buttonState;\n});\nfinal buttonProvider = Provider<ButtonState>((ref) {\n return ref.watch(_buttonState);\n});\nRun Code Online (Sandbox Code Playgroud)\n和
\nfinal _timeLeftProvider = Provider<String>((ref) {\n return ref.watch(timerProvider.state).timeLeft;\n});\nfinal timeLeftProvider = Provider<String>((ref) {\n return ref.watch(_timeLeftProvider);\n});\nRun Code Online (Sandbox Code Playgroud)\n我尝试使用_buttonStateand _timeLeftProvider ,据我所知,该应用程序运行正常。所以,我的问题是:
buttonProviderand timeLeftProvider?非常感谢!
\n2020-10-26 更新(main.dart代码和输出图像)
我的main.dart代码是:
import \'package:flutter/material.dart\';\nimport \'package:flutter_hooks/flutter_hooks.dart\';\nimport \'package:hooks_riverpod/hooks_riverpod.dart\';\nimport \'package:riverpod_timer_app/timer.dart\';\n\nfinal timerProvider = StateNotifierProvider<TimerNotifier>(\n (ref) => TimerNotifier(),\n);\n\nfinal _buttonState = Provider<ButtonState>((ref) {\n return ref.watch(timerProvider.state).buttonState;\n});\n\nfinal …Run Code Online (Sandbox Code Playgroud)