我在获取包含要在 ViewModel 中填充的对象列表的流时遇到问题。
- 从 Firestore 服务加载异步
Stream<List<Habit>>
在DailyViewModel
. - 调用转换方法将该流转换为查看特定流的
Stream<List<HabitCompletionViewModel>>
我今天每个习惯的实例,如果不存在,则创建该实例。这有几个组成部分:- 对于初始流中的每个习惯,运行一个私有方法,该方法检查今天是否存在该习惯的实例,如果没有,则初始化一个实例。这是一种异步方法,因为它回调数据库以使用新实例更新习惯。
- 然后找到今天的实例,并返回一个包含习惯和今天实例的
HabitCompletionViewModel
。 - 将这些映射到列表。
- 该新流在
DailyViewModel
的属性中设置为todaysHabits
。 todaysHabits
在DailyView
小组件中称为StreamBuilder
中的流。
我遇到的问题是,我知道今天正在找到完成。
我对什么可以/应该称为异步代码以及我是否在我的代码中使用正确的异步/异步* 返回/收益语句非常模糊,特别是因为我试图将此过程作为我的构造函数的一部分启动DailyViewModel
。我使用了一堆打印注释,似乎一切都在运行,但是我的 ViewModel 中的todaysHabits
始终设置为 null,并且 StreamBuilder 不返回任何项目。
我的代码中是否有可能导致此问题的异常?
DailyViewModel 具有以下 todaysHabits 属性,该属性加载在构造函数底部附近:
late Stream<List<HabitCompletionViewModel>> todaysHabits;
DailyViewModel({required WeekDates week}) {
_log.v('initializing the daily viewmodel');
_week = week;
_habitService
.loadActiveHabitsByUser(_loginAndUserService.loggedInUser!.id!)
.then(
(activeUserHabits) {
todaysHabits = _getTodaysHabits(activeUserHabits);
_log.v('todaysHabits has a length of ${todaysHabits.length}');
},
);
setBusy(false);
}
该构造函数调用此_getTodaysHabits函数,该函数应该将该Stream<List<Habit>>
转换为Stream<List<HabitCompletionViewModel>>
:
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
return habitsStream.asyncMap((habitsList) {
return Stream.fromIterable(habitsList).asyncMap(
(habit) async {
await _updateHabitWithNewCompletions(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) => completion.date
.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
}
我的视图(使用堆叠包来显示 ViewModel 的内容并相应地更新)包含此流构建器,它应该为每个HabitCompletionViewModel
返回磁贴列表:
StreamBuilder<List<HabitCompletionViewModel>>(
stream: vm.todaysHabits,
builder: ((context, snapshot) {
if (snapshot.hasData == false) {
return Center(child: Text('No Habits Found'));
} else {
return Column(children: [
ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) => HabitCompletionTile(
key: ValueKey(snapshot.data![i].habit.id),
vm: snapshot.data![i],
),
),
]);
}
})),
根据 pskink 的评论,我进行了以下似乎有效的更新。(当我切换到该视图时略有滞后),但它现在显示正确的数据。
基本上,问题似乎是我以前的代码返回了一个期货列表,而不仅仅是一个 HabitCompletionViewModel 的列表,并且使用 Future.wait 等待所有这些完成。
将列表到列表的映射拉出到一个单独的子方法(这里是主要方法):
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
return habitsStream.asyncMap(
(habitsList) async => await _mapHabitsToViewModel(habitsList));
}
更新了该子方法,使其首先返回一个 List
Future<List<HabitCompletionViewModel>> _mapHabitsToViewModel(
List<Habit> habitsList) async {
List<Future<HabitCompletionViewModel>> newList =
habitsList.map((habit) async {
HabitCompletion completion = habit.completions!.firstWhere((completion) =>
completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
}).toList();
List<HabitCompletionViewModel> transformed = await Future.wait(newList);
return transformed;
}