【发布时间】:2019-10-06 23:35:00
【问题描述】:
我需要实现搜索和显示结果。我使用来自 RxDart 的 Observables。
abstract class SearchState {}
class SearchCompleted extends SearchState {}
class SearchEmpty extends SearchState {}
final _searchSubject = PublishSubject<String>();
Observable<SearchState> get result {
return _searchSubject.switchMap((term) {
return _search(term); // returns Observable<SearchCompleted>
}).switchIfEmpty(Observable.just(SearchEmpty()));
}
StreamBuilder 中的某处使用此 result 作为 stream 的来源。在打开屏幕(没有搜索)我希望
snapshot.hasData = true
因为我的 observable 发出 SearchEmpty 但我得到 false。我做错了什么?如果搜索结果为空,我只需要显示一些消息。
UPD:在对 StreamBuilder 进行额外调查、阅读 RxDart 文档并从 pskink 中对信息进行系统化之后,我得出的结论是我弄错了。 switchIfEmpty() 表示只有在原始流不返回任何内容(将值放入 sink 之后)时,才会将流切换到回退。我需要使用 startWith() 来强制 observable 发出所需的 start 值。所以正确的代码是
Observable<SearchState> get result {
return _searchSubject.switchMap((term) {
return _search(term); // returns Observable<SearchCompleted>
}).startWith(SearchEmpty());
}
UPD2:在 first 构建小部件 StreamBuilder 的 snapshop.hasData = false 时,甚至使用 startWith() 因为 connectionStatus = ConnectionStatus.waiting(即当流准备接收数据时)。为避免这种情况,您必须设置 initialData 属性的值。例如:
StreamBuilder(
initialData: SearchEmpty(),
stream: result,
builder: ...
)
或者您可以在连接处于等待状态时返回一些小部件。例如:
StreamBuilder(
stream: result,
builder: (context, snapshot) {
// this allow to skip using `initialData`
if (snapshot.connectionStatus == ConnectionStatus.waiting) {
return Center(child: CircularProgressIndicator());
}
// Process data
if (snapshot.hasData) {
if (snapshot.data is SearchEmpty()) { return Text('no items');}
if (snapshot.data is SearchCompleted()) { return ListView(...);}
}
}
),
【问题讨论】:
-
如果什么也没找到,
search(term)会返回什么?Observable.empty()? -
我注意到如果我第一次打开页面(术语为空),代码流不会进入 switchMap(),即立即返回可观察结果并且 hasData = false。是的,当 _search() 没有找到记录时,它会返回 SearchEmpty()。但问题是为什么结果在开始时没有发出任何内容时不会切换到回退流。
-
试试这个并查看日志:
PublishSubject<String> subject = PublishSubject(); subject .switchMap((s) => _search(s).switchIfEmpty(Observable.just('*** NOT FOUND ***'))) .listen(print);- 使用假设的_search()方法测试它:Observable<String> _search(String term) { return term.length < 8 ? Observable.just('[$term]') : Observable.empty(); } -
我已经这样做了,但我没有看到任何输出。但是当我这样做时
_searchSubject.add('test')我看到了测试这个修改subject.switchMap((s) => _search(s)).switchIfEmpty(Observable.just('*** NOT FOUND ***')).listen(print);也没有给出响应。 -
正如我在上面的评论中提到的,我已经按照你的建议做了。我没有使用 TextController,而是直接将值发送到流。但是(我重复一遍:))问题是当什么都没有发送时,我在控制台中看不到 *** NOT FOUND ***。当流为空时,似乎不会触发此事件。 :(
标签: flutter observable rxdart