Flutter debounce api 在 rxdart vanilla bloc 中调用

Flutter debounce api call in rxdart vanilla bloc

我有一个 vanilla bloc,我正在其中实现无限列表视图。到目前为止,我已经这样做了。这是我的 bloc 实现,我像这样将数据加载到无限列表视图中。

class MyProductsBloc {
  final MyProductsRepo _repository = MyProductsRepo();
  final BehaviorSubject<MyProducts> _subject = BehaviorSubject<MyProducts>();
  int _page;
  getMyProducts() async {
    _page = 1;
    MyProducts response = await _repository.getProducts(page: 1);
    _subject.sink.add(response);
  }

  getMoreProducts() async {
    _page++;
    MyProducts response =
        await _repository.getProducts(page: _page);
    if (response.success) {
      _subject.value.maxPage = response.maxPage;
      _subject.value.pageNum = response.pageNum;
      _subject.value.data.addAll(response.data);
      _subject.sink.add(_subject.value);
    } else {
      _page--;
    }
  }

  dispose() {
    _subject?.close();
  }

  BehaviorSubject<MyProducts> get subject => _subject;
}

在 UI 部分,我使用的是 streambuilder,它有一个带有 notificationlistner 的列表视图来监听 scrollnotification。

StreamBuilder<MyProducts>(
                stream: myProductsBloc.subject.stream,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    if (snapshot.data.error != null &&
                        snapshot.data.error.length > 0) {
                      return ShowError(
                        error: snapshot.data.error,
                        onTap: () => myProductsBloc.getMyProducts(),
                      );
                    } else if (snapshot.data.data.length == 0) {
                      return EmptyWidget();
                    }
                    return NotificationListener<ScrollNotification>(
                      onNotification: (ScrollNotification scrollInfo) {
                        if (scrollInfo.metrics.pixels ==
                            scrollInfo.metrics.maxScrollExtent) {
                          if (snapshot.data.isEnd) {
                            return false;
                          } else {
                            myProductsBloc.getMoreProducts();
                          }
                        }
                        return false;
                      },
                      child: ListView(
                        children: [
                          ListView.separated(
                            primary: false,
                            shrinkWrap: true,
                            separatorBuilder: (context, i) =>
                                const SizedBox(height: 10),
                            padding: EdgeInsets.all(10),
                            itemCount: snapshot.data.data.length,
                            itemBuilder: (context, i) {
                              ProductData productData = snapshot.data.data[i];
                              return ProductCard(product: productData);
                            },
                          ),
                          LoadMoreIndicator(isEnd: snapshot.data.isEnd),
                        ],
                      ),
                    );
                  } else if (snapshot.hasError) {
                    return Center(
                      child: Text('${snapshot.data.error}'),
                    );
                  } else {
                    return Center(
                        child: LoadingWidget(text: "Fetching products.."));
                  }
                }),

但是当滚动时,api 被多次调用。有什么方法可以消除多次调用 api 的这种模式?



class MyProductsBloc {
  var _isLoading = false; <---- add this variable

  final MyProductsRepo _repository = MyProductsRepo();
  final BehaviorSubject<MyProducts> _subject = BehaviorSubject<MyProducts>();
  int _page;
  getMyProducts() async {
    _page = 1;
    MyProducts response = await _repository.getProducts(page: 1);
    _subject.sink.add(response);
  }

  getMoreProducts() async {
    if (_isLoading) return;
    _isLoading = true;
   
    try {
        _page++;
        MyProducts response = await _repository.getProducts(page: _page);
       if (response.success) {
         _subject.value.maxPage = response.maxPage;
         _subject.value.pageNum = response.pageNum;
         _subject.value.data.addAll(response.data);
         _subject.sink.add(_subject.value);
       } else {
         _page--;
       }
    } finally { _isLoading = false; }
  }

  dispose() {
    _subject?.close();
  }

  BehaviorSubject<MyProducts> get subject => _subject;
}