Stream/Bloc/Repository/Firebase 数据流 Flutter
Posted
技术标签:
【中文标题】Stream/Bloc/Repository/Firebase 数据流 Flutter【英文标题】:Stream/Bloc/Repository/Firebase data flow Flutter 【发布时间】:2020-06-07 09:29:30 【问题描述】:我从 Flutter 开始,因为我想将我的 swift 应用程序移植到 Flutter,但是我在学习 Bloc/Repository/Firebase 模式时遇到了困难,因为我正在学习https://bloclibrary.dev/#/flutterfirestoretodostutorialdough 我实时使用的教程数据库,而不是 Firestore。 我的 swift 应用程序基本上是一张地图,您可以在其中在实际坐标处添加警报。警报被发送到 Firebase,地图上的 firebase 观察者更新地图,显示刚刚添加的警报。 上面的教程应该可以帮助我移植我的应用程序。我只是不确定我是否理解代码背后的逻辑。 我的担忧是2:
首先。在模型对象和 firebase 对象之间有一个Entity
层。据解释,这将有助于拥有不同的数据提供者,但我并没有真正看到它有什么促进作用。 Model
类中有toEntity()
和fromEntity()
转换方法,Entity
类中有fromSnapshot()
和toDocument()
转换方法。我不明白这里有什么意义。真的有必要吗?直接在 Model
类中进行转换有什么问题,每个数据提供者都有不同的方法?
第二。在TodoBloc
内部,我无法遵循逻辑。
在AppStart
发送到集团的第一个事件是LoadTodos
。
BlocProvider<TodosBloc>(
create: (context)
return TodosBloc(
todosRepository: FirebaseTodosRepository(),
)..add(LoadTodos());
在TodoBloc
的mapEventToState()
方法中,该事件被映射到此流:
Stream<TodosState> _mapLoadTodosToState() async*
_todosSubscription?.cancel();
_todosSubscription = _todosRepository.todos().listen(
(todos) => add(TodosUpdated(todos)),
);
到目前为止一切顺利。据我了解,这订阅了todos()
Stream ()
@override
Stream<List<Todo>> todos()
return todoCollection.snapshots().map((snapshot)
return snapshot.documents
.map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc)))
.toList();
);
这应该相当于我的 swift 应用程序中的 firebase 观察者。 listen
闭包内的这部分我不确定:(todos) => add(TodosUpdated(todos))
。
这会向自身 (TodoBloc) 发送一个 TodosUpdated
事件,该 bloc 将在该事件上映射此 Stream:
Stream<TodosState> _mapTodosUpdatedToState(TodosUpdated event) async*
yield TodosLoaded(event.todos);
这是:
class TodosLoaded extends TodosState
final List<Todo> todos;
const TodosLoaded([this.todos = const []]);
@override
List<Object> get props => [todos];
@override
String toString() => 'TodosLoaded todos: $todos ';
这是 Firebase 对象的实际列表吗?每次在 Firebase 中添加新对象时,todos()
Stream 是否会返回整个节点?
在我的 swift 应用程序中,观察者在第一次下载节点后仅返回 .childAdded
。
我是否应该使用具有FirebaseList
类(https://pub.dev/documentation/firebase_database/latest/ui_firebase_list/FirebaseList-class.html) 的firebase_database
包,它只会在节点上的任何更改上返回一个列表,就像我的观察者在我的swift 应用程序中所做的那样?
很抱歉这个冗长而混乱的问题,但我从 bloc 模式开始就迷失了。
非常感谢您的时间和帮助。
【问题讨论】:
【参考方案1】:好的,我想我理解它背后的逻辑,但如果您发现我没有理解正确,请纠正我,因为在进入新范式的这个阶段,不要产生任何误解,这一点非常重要。
todos()
是来自 Firebase 的流并返回 List<Todo>
。
_mapLoadTodosToState()
是将 bloc 侦听器附加到 todos()
的 bloc 方法,在 .listen(onData)
回调中,它向 bloc 发送包含最新列表的 TodosUpdated(todos)
事件。
TodosUpdated(todos)
被映射到 _mapTodosUpdatedToState
,从而产生
TodosLoaded(event.todos)
,BlocProvider 用于构建 UI 的新状态。
谢谢你,我希望这能帮助其他人在更复杂的层面上努力掌握 BloC 模式。 干杯
【讨论】:
也需要一些时间来理解这种模式,但我得出了相同的结论。唯一我还不太了解的是如何在我的流加载数据时显示 LoadingIndicator。例如,如果我的 todos 上有一个过滤器,并且我使用 .where() 方法将查询更改为 firestore,或者互联网连接速度可能很慢,该怎么办? 一旦你习惯了它就会变得轻而易举.. 需要编写相当多的代码.. 但是有一个新的更简单的包 Cubit 。 .(还没有尝试过)它是一个更简单的 bloc 版本,可以集成到 bloc 实现中.. 非常感谢。我对 Riverpod 做了同样的事情,但不确定这是否是正确的方法。如果您熟悉 Riverpod,那么我在使用这种方法以获得更好的性能方面还有一些问题。如果你觉得舒服,我可以问这些问题吗? 嗨,我还没有研究过 Riverpod,但让我们试试吧,无论如何我可能会有所帮助 从流中获取数据后,我将其转换为包含更改通知列表的对象(比如说objA
)。因此,每当 Firestore 流获得新数据时,它将被转换为 objA
,添加到状态(在我的情况下为 StateNotifier
),并将发送到我们正在使用它的小部件。现在,如果对象相同或状态列表中的大多数项目相同,我只想更新已修改更改通知器中的更改,否则将重建所有对象。 (我知道如果它们相同,颤振会尽量不重建对象,但我们不能 100% 确定。)以上是关于Stream/Bloc/Repository/Firebase 数据流 Flutter的主要内容,如果未能解决你的问题,请参考以下文章