在BLOC事件后Streambuilder无法重建

问题描述

我正在尝试在我的应用程序中实现分页,但是没有成功。

我正在使用Firebase,特别是具有BLOC模式的Firestore,以及我最近开始使用的“内置价值”来简化分页

我非常感谢任何帮助或推荐链接如何一起使用这些技术。

我的应用程序体系结构如下:

Application Architecture

我试图尽可能地保持BLOC模式,但这反过来又使得很难进行大量分页,因为将内置值用作内置值使得使用流和期货真的很困难。我在Internet上四处查看,但找不到任何教程或文档来专门使用Firestore和BLOC的内置值进行分页

问题是,当我执行任何CRUD功能(例如,从列表中删除类别)时,尽管分页和其他所有功能正常工作,Stream Builder都不会更新列表。

当前,我尝试单独使用一个Listview构建器,该构建器显然根本不起作用,因此我移至Stream Builder,并尝试了Streams和Futures(.asstream),但未更新。

下面是一些代码

模型:

abstract class CategoryCard
    implements Built<CategoryCard,CategoryCardBuilder> {
  String get category;
  String get icon;
  double get budget;
  double get spent;
  String get categoryRef;
  DocumentSnapshot get document;

  CategoryCard._();

  factory CategoryCard([updates(CategoryCardBuilder b)]) = _$CategoryCard;

  static Serializer<CategoryCard> get serializer => _$categoryCardSerializer;
}

查询

  Future<Stream<fs.QuerySnapshot>> getMoreCategoryAmounts(
      fs.DocumentSnapshot documentSnapshot) async {
    var user = await getCurrentUser();

    print(currentMonth);

    fs.Query categoryAmountQuery = _instance
        .collection('users')
        .document(user.uid)
        .collection('amounts')
        .where('year',isEqualTo: currentYear)
        .where('month',isEqualTo: currentMonth)
        .orderBy('category',descending: false)
        .limit(7);

    return documentSnapshot != null
        ? categoryAmountQuery.startAfterDocument(documentSnapshot).snapshots()
        : categoryAmountQuery.snapshots();
  }

BLOC:

class CategoryCardBloc extends Bloc<CategoryCardEvents,CategoryCardState> {
  final BPipe bPipe;
  final FirebaseRepository firebaseRepository;

  CategoryCardBloc({@required this.bPipe,@required this.firebaseRepository})
      : assert(bPipe != null),assert(firebaseRepository != null);

  @override
  CategoryCardState get initialState => CategoryCardState.intial();

  @override
  Stream<CategoryCardState> mapEventToState(CategoryCardEvents event) async* {
    if (event is LoadCategoryCardEvent) {
      yield* _mapToEventLoadCategoryCard(event);
    }
  }

  Stream<CategoryCardState> _mapToEventLoadCategoryCard(
      LoadCategoryCardEvent event) async* {
    if (event.amountDocumentSnapshot == null) {
      yield CategoryCardState.loading();
    }
    try {
      Future<BuiltList<CategoryCard>> _newCategoryCards =
          bPipe.getMoreCategoryCards(event.amountDocumentSnapshot);

      yield CategoryCardState.loaded(
          FutureMerger()
              .merge<CategoryCard>(state.categoryCards,_newCategoryCards));
    } on NullException catch (err) {
      print('NULL_EXCEPTION');
      yield CategoryCardState.Failed(err.objectExceptionMessage,state?.categoryCards ?? Stream<BuiltList<CategoryCard>>.empty());
    } on NovalueException catch (_) {
      print('NO VALUE EXCEPTION');
      yield state.rebuild((b) => b..hasReachedEndOfDocuments = true);
    } catch (err) {
      print('UNKNowN EXCEPTION');
      yield CategoryCardState.Failed(
          err != null ? err.toString() : NullException.exceptionMessage,state.categoryCards);
    }
  }
}

国家:

abstract class CategoryCardState
    implements Built<CategoryCardState,CategoryCardStateBuilder> {
  Future<BuiltList<CategoryCard>> get categoryCards;
  //*Reached end indicator
  bool get hasReachedEndOfDocuments;
  //*Error state
  String get exception;
  //*Loading state
  @nullable
  bool get isLoading;
  //*Success state
  @nullable
  bool get isSuccessful;
  //*Loaded state
  @nullable
  bool get isLoaded;

  CategoryCardState._();

  factory CategoryCardState([updates(CategoryCardStateBuilder b)]) =
      _$CategoryCardState;

  factory CategoryCardState.intial() {
    return CategoryCardState((b) => b
      ..exception = ''
      ..isSuccessful = false
      ..categoryCards =
          Future<BuiltList<CategoryCard>>.value(BuiltList<CategoryCard>())
      ..hasReachedEndOfDocuments = false);
  }

  factory CategoryCardState.loading() {
    return CategoryCardState((b) => b
      ..exception = ''
      ..categoryCards =
          Future<BuiltList<CategoryCard>>.value(BuiltList<CategoryCard>())
      ..hasReachedEndOfDocuments = false
      ..isLoading = true);
  }
  factory CategoryCardState.loaded(Future<BuiltList<CategoryCard>> cards) {
    return CategoryCardState((b) => b
      ..exception = ''
      ..categoryCards = cards
      ..hasReachedEndOfDocuments = false
      ..isLoading = false
      ..isLoaded = true);
  }
  factory CategoryCardState.success(Future<BuiltList<CategoryCard>> cards) {
    return CategoryCardState((b) => b
      ..exception = ''
      ..categoryCards =
          Future<BuiltList<CategoryCard>>.value(BuiltList<CategoryCard>())
      ..hasReachedEndOfDocuments = false
      ..isSuccessful = true);
  }
  factory CategoryCardState.Failed(
      String exception,Future<BuiltList<CategoryCard>> cards) {
    return CategoryCardState((b) => b
      ..exception = exception
      ..categoryCards = cards
      ..hasReachedEndOfDocuments = false);
  }
}

事件:

abstract class CategoryCardEvents extends Equatable {}

class LoadCategoryCardEvent extends CategoryCardEvents {
  final DocumentSnapshot amountDocumentSnapshot;

  LoadCategoryCardEvent({@required this.amountDocumentSnapshot});

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

分页屏幕(包含在有状态的小部件中):

//Notification Handler
  bool _scrollNotificationHandler(
      ScrollNotification notification,DocumentSnapshot amountDocumentSnapshot,bool hasReachedEndOfDocuments,Future<BuiltList<CategoryCard>> cards) {
    if (notification is ScrollEndNotification &&
        _scollControllerHomeScreen.position.extentAfter == 0 &&
        !hasReachedEndOfDocuments) {
      setState(() {
        _hasReachedEnd = true;
      });

      _categoryCardBloc.add(LoadCategoryCardEvent(
          amountDocumentSnapshot: amountDocumentSnapshot));
    }
    return false;
  }


BlocListener<CategoryCardBloc,CategoryCardState>(
                    bloc: _categoryCardBloc,listener: (context,state) {
                      if (state.exception != null &&
                          state.exception.isNotEmpty) {
                        if (state.exception == NullException.exceptionMessage) {
                          print('Null Exception');
                        }  else {
                          ErrorDialogs.customAlertDialog(
                              context,'Failed to load','Please restart app or contact support');

                          print(state.exception);
                        }
                      }
                    },child: BlocBuilder<CategoryCardBloc,CategoryCardState>(
                        bloc: _categoryCardBloc,builder: (context,state) {
                          if (state.isLoading != null && state.isLoading) {
                            return Center(
                              child: Customloader(),);
                          }

                          if (state.isLoaded != null && state.isLoaded) {
                            return StreamBuilder<BuiltList<CategoryCard>>(
                              stream: state.categoryCards.asstream(),snapshot) {

                                if (!snapshot.hasData) {
                                  return Center(
                                    child: Customloader(),);
                                } else {
                                  BuiltList<CategoryCard> categoryCards =
                                      snapshot.data;

                                  _hasReachedEnd = false;

                                  print(state.hasReachedEndOfDocuments &&
                                      state.hasReachedEndOfDocuments != null);

                                  return Container(
                                    height: Mquery.screenHeight(context),width: Mquery.screenWidth(context),child: NotificationListener<
                                        ScrollNotification>(
                                      onNotification: (notification) =>
                                          _scrollNotificationHandler(
                                              notification,categoryCards.last.document,state.hasReachedEndOfDocuments,state.categoryCards),child: SingleChildScrollView(
                                        controller: _scollControllerHomeScreen,child: Column(
                                          children: [
                                            CustomAppBar(),Padding(
                                              padding: EdgeInsets.all(
                                                  Mquery.padding(context,2.0)),child: Row(
                                                children: [
                                                  Expanded(
                                                    flex: 5,child: Padding(
                                                      padding: EdgeInsets.all(
                                                          Mquery.padding(
                                                              context,1.0)),child:Container(
                                                          width: Mquery.width(
                                                              context,50.0),height: Mquery.width(
                                                              context,12.5),decoration:
                                                              Boxdecoration(
                                                            color: middle_black,borderRadius: BorderRadius
                                                                .circular(Constants
                                                                    .CARD_BORDER_RADIUS),BoxShadow: [
                                                              BoxShadow(
                                                                  color: Colors
                                                                      .black54,blurRadius:
                                                                      4.0,spreadRadius:
                                                                      0.5)
                                                            ],),child: Padding(
                                                            padding: EdgeInsets.fromLTRB(
                                                                Mquery.padding(
                                                                    context,4.0),Mquery.padding(
                                                                    context,2.0),child: TextField(
                                                              textInputAction:
                                                                  TextInputAction
                                                                      .done,style: TextStyle(
                                                                  color: white,fontSize: Mquery
                                                                      .fontSize(
                                                                          context,4.25)),controller:
                                                                  searchController,decoration:
                                                                  Inputdecoration(
                                                                border:
                                                                    InputBorder
                                                                        .none,hintText: Constants
                                                                    .SEARCH_MESSAGE,hintStyle: TextStyle(
                                                                    fontSize: Mquery
                                                                        .fontSize(
                                                                            context,4.25),color:
                                                                        white),Expanded(
                                                      flex: 1,child: Padding(
                                                        padding: EdgeInsets.all(
                                                            Mquery.padding(
                                                                context,child: Container(
                                                          decoration:
                                                              Boxdecoration(
                                                            BoxShadow: [
                                                              BoxShadow(
                                                                  color: Colors
                                                                      .black54,color: middle_black,width: Mquery.width(
                                                              context,child: IconButton(
                                                            splashColor: Colors
                                                                .transparent,highlightColor:
                                                                Colors
                                                                    .transparent,icon: Icon(
                                                              Icons.search,color: white,onpressed: () {
                                                              _onSearchButtonpressed();
                                                            },))
                                                ],ListView.builder(
                                              shrinkWrap: true,itemCount: categoryCards.length,physics:
                                                  NeverScrollableScrollPhysics(),itemBuilder: (context,index) {
                                                return GestureDetector(
                                                    onTap: () {
                                                      //Navigate
                                                    },child:
                                                        CategoryCardWidget(
                                                            categoryCount:
                                                                categoryCards
                                                                    .length,categoryCard:
                                                                categoryCards[
                                                                    index]));
                                              },_hasReachedEnd
                                                ? Padding(
                                                    padding: EdgeInsets.all(
                                                        Mquery.padding(
                                                            context,4.0)),child: Customloader(),)
                                                : Container()
                                          ],);
                                }
                              },);
                          }

                          return Container();
                        }))

感谢您的时间,并很抱歉如此冗长

  • 马特

解决方法

我设法解决了这个问题,

下面是Github链接: https://github.com/felangel/bloc/issues/1707

希望对某人有帮助! -马特

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...