我的Flutter应用具有以下一般结构:
我正在使用FireStore。该列表是用Stream<QuerySnapshots>
构建的,当用户点击一个项目时,应用程序的路由器解析路由名称(例如/contacts/123
),创建相应的DocumentReference
并将其转发到详细信息屏幕的初始化程序,然后使用DocumentReference.get
加载详细信息,并使用DocumentReference.updateData
保存更改。效果很好–但这仅仅是概念的证明。
现在,我想将FireStore和其余的业务逻辑隐藏在BLoC后面。这导致了一些问题:
streamOfContact(contact) -> Stream<Contact>
之类的功能),那么我将如何使用Sink?还是在不破坏BLoC模式的情况下通常有其他方法可以做到这一点?我对所有这些都是新手,所以很可能我忽略了一些重要的事情。我在网上找到的教程仅处理根数据(例如,将购物车中的商品添加到购物车,处理用户身份验证等),但是我还没有看到展示嵌套数据的示例。非常感谢您的帮助!
答案 0 :(得分:8)
1)路由和导航由UI层负责。这意味着UI层必须调用Navigator.push[Named](...)
。
如果有道理,您可以移动决定应用程序是否应导航到详细信息屏幕的逻辑:
// in the BLoC:
Stream<int> showContactDetail;
// in the UI layer:
bloc.showContactDetail.listen(_showContactDetail);
如何将参数传输到详细路线完全取决于您。您可以使用命名路由,但是使用构建器传输数据会更容易:
void _showContactDetail(int contactId) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
return ContactDetailPage(
contactId: contactId,
);
}));
}
2)一个BLoC应该绑定到一个屏幕,这意味着详细信息屏幕(或对话框/边栏/ ...)应该有一个单独的BLoC,并将您的联系人ID传递给第二个BLoC作为构造函数参数,或者使用StreamSink
,或者使用简单的setter方法。
我建议您对BLoC输入使用普通的旧方法,而不要使用StreamSink
。 Here是关于该主题的最新讨论。
3)问题不仅是如何从详细信息屏幕更新您的联系人,而且还包括详细信息BLoC如何获取联系人数据(如果您仅传输联系人ID)。
答案:所有BLoC之间共享的另一个应用程序层,我称为数据层。您可以将数据存储在Firebase,sqlite数据库或简单的Map<int, Contact>
中。
数据层还将更改传播到后端,并在数据更改后通知所有BLoC,可能使用Stream
。
接下来要提出的问题是将数据层放置在哪里(例如,名为ContactService
的类):
ContactService
中创建ContactListPage
,然后将其传递给构造函数参数中的ContactDetailPage
(使用路由生成器,如上所述)。这里没有魔术。您可能不希望出现的副作用是,当弹出列表页面时,该服务将被丢弃。InheritedWidget
,位于MaterialApp
上方,或至少位于Navigator
生成的MaterialApp
上方(您可以使用{{1 }},以使用您自己的小部件包装导航器)。将其高高地放在树中可确保您应用的所有页面都可以访问它。