事件管理颤动集团模式

Posted

技术标签:

【中文标题】事件管理颤动集团模式【英文标题】:events management flutter bloc pattern 【发布时间】:2021-08-15 07:20:15 【问题描述】:

每个人。我是 Flutter 和 BLoC 模式的新手。

我需要实现联系人页面,所以我创建了事件 GetContacts 并将其传递到 context.read().add() 之后,我将此事件调用到联系人屏幕的 initState() 中。

这是我的活动:


abstract class ContactEvent extends Equatable 
  const ContactEvent([List props = const []]) : super();


class GetContacts extends ContactEvent 

  const GetContacts() : super();

  @override
  List<Object> get props => [];
 

这是我的集团:

class ContactsBloc extends Bloc<ContactEvent, ContactsState> 
  final ContactsRepo contactsRepo;
  ContactsBloc(required this.contactsRepo) : super(ContactInitial());

  @override
  Stream<ContactsState> mapEventToState(ContactEvent event,) async* 
    yield ContactsLoading();
    //
    // if (event is UpdatePhoto) 
    //   yield PhotoLoading();
    //
    //   print("LOADING STARTED");
    //
    //   final photo = await contactsRepo.updatePhoto(event.identifier, event.photo);
    //   print("LOADING FINISHED");
    //
    //   yield PhotoLoaded(photo: photo);
    // 
    if (event is GetContacts) 
      print("get contacts photoBloc");
      try 

        final contacts = await contactsRepo.getContacts();
        yield ContactsLoaded(contacts);
       on AccessException 
        yield ContactsError();
      
    
  
 

这工作正常,联系人页面按预期呈现联系人。

[联系人屏幕][1] [1]:https://i.stack.imgur.com/Gx3JA.png

但后来我决定实施新功能:当用户点击任何联系人时,他会被要求更改其照片。 如果我正确理解 BLoC 模式,那么如果我想改变我的状态,我需要创建新事件。然后我创建了新动作 UpdatePhoto 并将其传递到与第二部分代码(在 cmets 中)所示相同的 Bloc 中。正是在那里,我遇到了对架构扩展的误解。此操作不应该返回 ContactsLoaded 状态,因此当我尝试将其捕获到我的另一个 bloc 构建器中时,它破坏了我之前捕获 GetContact 事件的 bloc 构建器。

联系状态:

abstract class ContactsState extends Equatable 
  const ContactsState([List props = const []]) : super();



// class PhotoLoading extends PhotoState 
//   @override
//   List<Object?> get props => [];
// 
//
// class PhotoLoaded extends PhotoState 
//   final Uint8List photo;
//   const PhotoLoaded(required this.photo);
//   @override
//   List<Object?> get props => [photo];
// 

class ContactInitial extends ContactsState 
  @override
  List<Object> get props => [];


class ContactsLoading extends ContactsState 
  @override
  List<Object> get props => [];


class ContactsLoaded extends ContactsState 
  final List<MyContact> contacts;
  ContactsLoaded(this.contacts) : super([contacts]);

  @override
  List<Object> get props => [contacts];


class ContactsError extends ContactsState 
  @override
  List<Object?> get props => [];

问题:如果我想创建新事件(例如 UpdatePhoto),它不应该返回我之前在同一个 bloc 中捕获的状态,那么我需要为此创建新 bloc 并通过 multiProvider 覆盖我的屏幕?

【问题讨论】:

【参考方案1】:

我想在 BlocBuilder 中使用可选参数 buildWhen 是避免为每个事件创建新 bloc 的最佳方法。

【讨论】:

【参考方案2】:

您还应该发布您的 ContactState 代码。

但是,您不一定需要新的 Bloc。这完全取决于您要达到的目标。 我想当你yield PhotoLoading() 你想展示一个加载器时。 但是,当您更新照片时,如果我了解您要达到的目的,您应该再次使用 yield ContactsLoaded(contacts)add(GetContacts()) 而不是 yield PhotoLoaded(photo: photo) 生成更新的联系人列表。 如果您想显示确认消息,您可以保持 PhotoLoaded 状态,但您需要在构建 UI 时考虑到 bloc 可能发出的不同状态。

请记住,在 BloC 架构中,事件可以连续产生多个状态,并且 UI 决定是否以及如何对每个状态做出反应。

【讨论】:

是的。 PhotoLoading 表示我要显示加载器。但是,当显示加载器时,我不想隐藏联系人页面,我只想更改 1 个联系人,所以如果在加载时只有一个联系人被加载器替换,这可能吗?如果我对问题的解释有点愚蠢,我很抱歉 或者,如果我的 BlocBuilder 只对一个特殊事件(不是所有事件)做出反应,也许有可能 当然可以只为特殊状态构建(不是你说的事件,UI 只对状态做出反应)。那是 buildWhen 参数。但是您可能希望收到未更新的联系人列表以显示带有新照片的新列表... 为了只在一个项目上使用加载器来实现你想要的,我确实会构建一个新的 Bloc 来管理单个项目......所以你会有一个 Bloc 提供者,你的列表 Bloc 在你的顶部小部件树和每个联系人小部件的项目块,每个小部件负责管理单个联系人磁贴的 UI。但即使使用此实现,您仍可能需要在 List Bloc 中生成联系人更新状态,以通知 UI 必须更新其中一个联系人 感谢您的建议,我猜 buildWhen 参数正是我找到的。 :)

以上是关于事件管理颤动集团模式的主要内容,如果未能解决你的问题,请参考以下文章

重置块颤动中的事件和状态

当应用程序在颤动中被杀死/终止时,从后台事件启动应用程序

列表容器&事件链如何帮业务提升发版迭代效率? | DX研发模式

Flutter BLoC 模式 - 如何在流事件后导航到另一个屏幕?

拒绝后权限请求颤动应用程序

JS高阶---事件循环模式(事件轮询)