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;
}
我有一个 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;
}