我是 Dart/Flutter 的新手,在“参加”了 Udemy 课程之后,一切都很顺利。到现在 ;-)
与 Udemy 课程中的示例应用程序一样,我使用的是 BLOC 模式。
像这样:
class App extends StatelessWidget {
Widget build(context) {
return AppBlocProvider(
child: MaterialApp(
(请参阅我稍后用来获取“AppBloc”的“AppBlocProvider”)
该应用程序以及所有屏幕都是 StatelessWidget 的。
AppBlocProvider 扩展了 InheritedWidget。像这样:
class AppBlocProvider extends InheritedWidget {
final AppBloc bloc;
AppBlocProvider({Key key, Widget child})
: bloc = AppBloc(),
super(key: key, child: child);
bool updateShouldNotify(_) => true;
static AppBloc of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(AppBlocProvider) as AppBlocProvider).bloc;
}
}
AppBlocProvider 提供了一个“AppBloc”,其中包含两个进一步的块以将不同的数据分开一点。像这样:
class AppBloc {
//Variables holding the continuous state
Locale appLocale;
final UserBloc userBloc;
final GroupsBloc groupsBlock;
在我的应用程序中,我有一个只有一个输入字段的“GroupSearchScreen”,您可以在其中输入组名的片段。单击按钮时,将完成 REST API 调用并返回组名列表。
与示例应用程序一样,我也将数据放入流中。
在示例应用程序中,数据获取并将其放入流中是在块本身中完成的。在下一行,创建了使用数据的屏幕。像这样:
//Collecting data and putting it in the stream
storiesBloc.fetchTopIds();
//Creating a screen ths shows a list
return NewsList();
然而,就我而言,有两个主要区别:
在 GroupSearchScreen 中收集数据后,我调用/创建 GroupsListScreen,其中应显示组列表,使用常规路由。像这样:
//向流中添加数据(“changeGroupList”提供了流的添加功能!) appBloc.groupsBlock.changeGroupList(groups); //调用/创建屏幕以显示组列表 Navigator.pushNamed(context, '/groups_list');
在创建的 GroupsListScreen 中,我获取了 bloc。像这样:
小部件构建(上下文){ final AppBloc appBloc = AppBlocProvider.of(context);
这些是路线:
Route routes(RouteSettings settings) {
switch (settings.name) {
case '/':
return createLoginScreen();
case '/search_group':
return createSearchGroupScreen();
case '/groups_list':
return createGroupsListScreen();
default:
return null;
}
}//routes
而“/groups_list”指向这个函数:
Route createSearchGroupScreen() {
return MaterialPageRoute(
builder: (context) {
//Do we need a DashboardScreen BLOC?
//final storiesBloc = StoriesProvider.of(context);
//storiesBloc.fetchTopIds();
return GroupSearchScreen();
}
);
}
如您所见,“AppBlocProvider”仅使用一次。(我也遇到了这个问题;-)
现在解决问题:
当 GroupsListScreen 开始渲染列表时,流/快照没有数据!
(参见“如果(!snapshot.hasData)”)
Widget buildList(AppBloc appBloc) {
return StreamBuilder(
stream: appBloc.groupsBlock.groups,
builder: (context, AsyncSnapshot<List<Map<String, dynamic>>>snapshot) {
if (!snapshot.hasData) {
为了测试 bloc 中的所有数据是否丢失,我尝试不将数据直接放入流中,而是放入成员变量中(在 bloc 中!)。
在 GroupSearchScreen 中,我将 json 数据放在 bloc 的成员变量中。
现在,就在 GroupsListScreen 开始渲染列表之前,我将数据 (json) 从 bloc 中取出,放入流中,它仍然驻留在 bloc 中,一切正常!快照有数据...
像这样(在 GroupsListScreen 中):
//Add data to Stream
appBloc.groupsBlock.changeGroupList(appBloc.groupsBlock.groupSearchResult);
当普通成员变量不是时,为什么流在从“GroupSearchScreen”到“GroupsListScreen”的过程中“丢失”其数据?两者都在同一个集团!
在 GroupsListScreen 的构建方法开始时,我有一个打印语句。因此,我可以看到 GroupsListScreen 构建了两次。这应该是正常的,但这可能是在流中找不到数据的原因吗?流听了两次吗?
Widget buildList(AppBloc appBloc) {
return StreamBuilder(
stream: appBloc.groupsBlock.groups,
我试图以这种方式解释我的问题,而不是提供大量代码。但我不知道是否足以提示我可以在哪里继续搜索......
更新 16.04.2019 - 解决方案:
我使用 Udemy 课程中看到的另一个应用程序构建了我的第一个应用程序......
“他的”应用程序和我的应用程序之间最重要的区别是他创建了监听流然后将数据添加到流中的 Widget。
我将数据添加到流中,然后导航到显示数据的小部件。
不幸的是,我使用了 RX-Dart “PublishSubject”。如果您收听那个,您将获得从您开始收听的那一刻开始放入流中的所有数据!
然而,RX-Dart "BehaviorSubject" 也会在您开始收听之前为您提供最后的数据。
这就是我在这里需要的行为:
将数据放在流上
创建小部件并开始收听
我可以鼓励所有 Flutter 新手阅读这两个非常好的教程:
https://medium.com/flutter-community/reactive-programming-streams-bloc-6f0d2bd2d248
https://www.didierboelens.com/2018/12/reactive-programming---streams---bloc---practical-use-cases/
在第一个中,提到的两个流都得到了很好的解释。