如何获取转换后的 Stream<List<Object>> 以使用异步代码显示数据?



我在获取包含要在 ViewModel 中填充的对象列表的流时遇到问题。

  1. 从 Firestore 服务加载异步Stream<List<Habit>>DailyViewModel.
  2. 调用转换方法将该流转换为查看特定流的Stream<List<HabitCompletionViewModel>>我今天每个习惯的实例,如果不存在,则创建该实例。这有几个组成部分:
    1. 对于初始流中的每个习惯,运行一个私有方法,该方法检查今天是否存在该习惯的实例,如果没有,则初始化一个实例。这是一种异步方法,因为它回调数据库以使用新实例更新习惯。
    2. 然后找到今天的实例,并返回一个包含习惯和今天实例的HabitCompletionViewModel
    3. 将这些映射到列表。
  3. 该新流在DailyViewModel的属性中设置为todaysHabits
  4. todaysHabitsDailyView小组件中称为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.wait 等待这些作为 HabitCompletionViewModels 完成,然后再返回该新列表:

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;
}

最新更新