我正在尝试在使用 Provider 管理的 Flutter 应用程序中实现本地数据库支持,现在我想让数据检索遵循状态管理模式,但我一直没有做到。
我试图制作一个传统的 Provider 来实现这一点,但该应用程序陷入了对数据库的请求循环中,所以经过一番搜索我找到了 FutureProvider,但我找不到如何从正在加载的数据中获取快照
class _ReceiptsRouteState extends State<ReceiptsRoute> {
List<Receipt> receipts = [];
@override
Widget build(BuildContext context) {
return FutureProvider(
initialData: List(),
builder: (_){
return DBProvider().receipts().then((result) {
receipts = result;
});
},
child: Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).history),
),
body: Container(
child: ListView.builder(
itemBuilder: (context, position) {
final item = receipts[position];
return ListTile(
title: Text(item.date),
);
},
),
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的应用程序正在按我想要的方式运行,但不是按照它应该如何运行,我使用 FutureBuilder 直接从数据库中获取数据,但我知道它应该通过提供程序来,所以我想使它正确
本周我开始在 flutter 中进行开发,但我无法解决这个问题。
\n\n我正在构建一个登录页面,该页面调用 API 进行登录,然后重定向到主页。\n这是第一个代码块中生成的异常。Navigator.pushReplacement\n此时apiCall.isFetching为 false,导致获取结束并apiCall.response包含所需的数据。
异常详细信息:
\n\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90 Exception caught by widgets library \xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\nThe following assertion was thrown building Consumer<ApiCallChangeNotifier>(dirty, dependencies: [InheritedProvider<ApiCallChangeNotifier>]):\nsetState() or markNeedsBuild() called during build.\n\nThis Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. …Run Code Online (Sandbox Code Playgroud) 我正在尝试实现 Provider ,它似乎工作正常,但我收到以下消息:
这个 _DefaultInheritedProviderScope 小部件不能被标记为需要构建,因为框架已经在构建小部件的过程中。仅当其祖先之一当前正在构建时,才可以将小部件标记为需要在构建阶段构建。允许此异常是因为框架在子级之前构建父级小部件,这意味着将始终构建脏后代。否则,框架可能不会在此构建阶段访问此小部件。调用 setState() 或 markNeedsBuild() 的小部件是: _DefaultInheritedProviderScope 值:“UserProfile”监听值的实例 进行违规调用时当前正在构建的小部件是:FutureBuilder 脏状态:_FutureBuilderState#bf6ec 当抛出异常,
0 元素.markNeedsBuild。(包:flutter/src/widgets/framework.dart:3896:11)
1 Element.markNeedsBuild(包:flutter/src/widgets/framework.dart:3911:6)
2 _InheritedProviderScopeMixin.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:268:5)
3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:206:21)
4 UserProfile.user= (package:mdd/core/services/user_info.dart:13:5) ... UserProfile
发送通知是:“UserProfile”的实例
我的代码如下:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final authService = Provider.of<AuthService>(context);
final userProfile = Provider.of<UserProfile>(context);
return StatefulWrapper(
onInit: () {
FirebaseNotifications().setUpFirebase();
},
child: FutureBuilder<User>(
future: authService.getUser(),
builder: (context, AsyncSnapshot<User> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
return Text(snapshot.error.toString());
}
userProfile.user …Run Code Online (Sandbox Code Playgroud) 在 Riverpod文档中,它说:
这
context.read(myProvider)就是解决方案的地方。使用它,我们可以将之前的代码重构为:
Run Code Online (Sandbox Code Playgroud)@override Widget build(BuildContext context) { return RaisedButton( onPressed: () => context.read(counterProvider).state++, child: Text('increment'), ); }通过这样做,点击我们的按钮仍然会增加计数器。但是我们不再听取提供者的意见,这避免了不必要的重建。
但后来它说:
警告
避免
context.read在buildWidget的方法内部调用。如果要优化重建,请提取在 Provider 中侦听的值。
这让我有点困惑。首先,文档给出了context.read在build方法内部使用的示例,然后给出了避免它的警告。为什么?
我正在使用 flutter_provider 进行状态管理。我想从 Api 加载页面(statefulwidget)上的一些项目。我在页面开始时显示一个加载程序,并希望在获取项目后显示它们。
播放列表.dart -
class Playlist extends StatefulWidget {
@override
_PlaylistState createState() => _PlaylistState();
}
class _PlaylistState extends State<Playlist> {
var videosState;
@override
void initState() {
super.initState();
videosState = Provider.of<VideosProvider>(context);
videosState.fetchVideosList();
}
@override
Widget build(BuildContext context) {
var videos = videosState.playlist;
return Scaffold(
appBar: AppBar(
title: Text('My Videos'),
),
body: RefreshIndicator(
child: Container(
width: double.infinity,
height: double.infinity,
child: videos.length
? ListView.builder(
itemBuilder: (BuildContext context, index) {
return _videoListItem(context, index, videos, videosState);
},
itemCount: videos.length,
)
: Center( …Run Code Online (Sandbox Code Playgroud) 我Provider在我的 flutter 应用程序中使用,当我转到一个新页面时,Provider在第 2 页中无法访问提供给第 1页的数据。
我理解这种Provider工作方式的方式是,有一个中心位置可以存储所有数据,并且可以在应用程序的任何位置访问该数据。所以在我的应用程序中,如下所示,ToDoListManager是存储所有数据的地方。如果我在 中设置数据Page 1,那么我将能够在 中访问该数据Page 2,反之亦然。
如果这不正确,那么哪部分是错误的?为什么它在我的应用程序中不起作用?
这是代码
第 1 页
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (context) => ToDoListManager(),
child: Scaffold(
appBar: AppBar(
title: Text('Cool Project'),
),
body:e ToDoList(),
),
);
}
}
class ToDoList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final toDoListManager = Provider.of<ToDoListManager>(context);
return ListView.builder(
itemCount: toDoListManager.toDoList.length,
itemBuilder: (context, index) { …Run Code Online (Sandbox Code Playgroud) 有时我认为我已经理解了提供者的逻辑,然后我在尝试做下面的事情时被难住了几个小时。
我需要从 firestore collectionsstream 获取连接 ID 列表。简单的。
但是,我需要将这个连接 ID 的流列表提供到另一个 Firestore 集合流中。下面,您可以看到我即将推出的EventsStreamProvider 是 ref.watch 数据库和connectionsStream。Riverpod 或 firestore 没有抛出任何错误。但是,在日志中,我按以下顺序看到打印语句:
returned data
returned null stream value
Run Code Online (Sandbox Code Playgroud)
我如何滥用 Riverpod 提供商的权力?哈哈。
final connectionsStreamProvider = StreamProvider<List<UidConnections>>((ref) {
final database = ref.watch(databaseProvider);
return database != null ? database.connectionsStream() : Stream.value(null);
});
final connectionsListStateProvider = StateProvider<List>((ref) => []);
final upcomingEventsStreamProvider = StreamProvider<List<SpecialEvents>>((ref) {
final database = ref.watch(databaseProvider);
final connectionsStream = ref.watch(connectionsStreamProvider);
if (database != null && connectionsStream != null) {
connectionsStream.whenData((data) {
if (data != null) { …Run Code Online (Sandbox Code Playgroud) 因此,我使用auto_route包在我的应用程序中进行导航和flutter_bloc状态管理。当我使用旧的 Navigator 时,我可以用 BlocProvider 包装一条路线。例如:
class Router {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => BlocProvider( // wrapped Home with BlocProvider
create: (context) => SubjectBloc(),
child: Home(),
),
);
case '/feed':
return MaterialPageRoute(builder: (_) => Feed());
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,auto_route使用注释来生成路由文件。我将如何绕过为路线提供提供者上下文?
Pusher在我们的系统中,我们在我们的Admin Panel和mobile应用程序上使用,flutter我想用 和 包装整个应用程序屏幕,Pusher并在屏幕中Riverpod使用带有小部件的提供程序Hook,这意味着我想在我们拥有的所有屏幕上实现Pusher或广播接收main到MyApp的数据Pusher它们,基本上我们必须Pusher在需要接收数据的每个屏幕中使用,并且其难以维护应用程序,例如:
这个示例代码不正确,我尝试实现它,但我不能
在这里,您可以看到Pusher事件和侦听器工作正常,没有任何问题:
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): [BIND] new-login
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): [BIND] new-login
D/PusherClientPlugin( …Run Code Online (Sandbox Code Playgroud) 我正在编写我的第一个 Flutter 应用程序,并正在努力应对各种状态管理解决方案。我决定从 Provider 开始,但我正在考虑切换到 BLoC。到目前为止,我发现的大多数示例都仅限于相对简单的事情,例如显示项目列表或响应某些按钮按下。就我而言,几乎所有应用程序都专注于设置相当大的数据块。(它基本上是一大堆表单,所有表单都在大型数据结构的不同位上工作。)
目前,所有状态管理都被放在一个提供程序类中,因为其中大部分都非常密切相关。例如,它的最大部分是一个项目列表,然后是该列表的一堆子集。应用程序中的大部分数据操作都在这些子集上。
我一开始并没有真正打算这样做,但我发现自己将实际使用提供程序的代码放在非常接近顶层的位置,然后沿着树传递数据。它违背了 Provider 的初衷,但它减少了重复的代码。例如,我的应用程序中的一个屏幕有一堆卡片,它们都包含非常相似的列表。它们之间的主要区别在于它们的内容来自不同的列表。因此,为了减少重复的代码,我尽可能地概括了卡片和列表,并将必要的数据沿树向下传递。我还传递回调函数来处理诸如编辑项目或将其从列表中删除之类的事情。
这听起来是一个不错的方法吗?事实上,我在树上传递状态和回调对我来说就像一种代码味道,但正如我所提到的,它减少了重复的代码。如果我有一个提供者暴露了很多东西,那又如何呢?我觉得我应该将数据模型与提供者分开,然后拥有多个较小的提供者。如果我要走这条路,BLoC 会比 Provider 更合适吗?如果我能够分解单一提供商,是否可能会提高性能?拥有多个提供商或集团似乎会使保存更改变得复杂,但也许并非如此。你有没有发现这是一个问题?
编辑:我刚刚发现这个问题,它讨论了不同数据的重用提供程序:Flutter Provider。如何拥有同一提供者类型的多个实例?
我以前并没有真正这么想过,但这是我正在努力解决的一个重要问题。我有独立修改的不同列表。它是在多个地方使用的相同小部件(有时在同一屏幕上),并且如果我将所拥有的内容分解成更小的部分,则提供程序中的功能也将是相同的。由于 Provider 是基于类型而不是实例,因此在这种情况下它可能不起作用。