Android 在Place API适配器中的Filter.performFiltering()中使用Rx debounce运算符
我们的应用程序使用AutoCompleteTextView和Google places API搜索地点 我想添加debounce RxJava操作符来放置搜索。我不太擅长RxJava 适配器已实现getFilter(),并且筛选器具有performFiltering()覆盖,该覆盖将约束/查询作为字符串接收。Android 在Place API适配器中的Filter.performFiltering()中使用Rx debounce运算符,android,rx-java,google-places-api,debounce,Android,Rx Java,Google Places Api,Debounce,我们的应用程序使用AutoCompleteTextView和Google places API搜索地点 我想添加debounce RxJava操作符来放置搜索。我不太擅长RxJava 适配器已实现getFilter(),并且筛选器具有performFiltering()覆盖,该覆盖将约束/查询作为字符串接收。 过滤器当前看起来如下所示: private inner class AutocompleteFilter : Filter() { @WorkerThread overr
过滤器当前看起来如下所示:
private inner class AutocompleteFilter : Filter() {
@WorkerThread
override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
val results = Filter.FilterResults()
val search = constraint?.toString() ?: ""
var found = emptyList<PlaceData>()
// quick reply on empty search
val bounds = latLngBounds
if (!TextUtils.isEmpty(search) && bounds != null) {
found = placesApiHelper.fetchAutocompletePredictions(search, bounds)
.timeout(1000L, TimeUnit.MILLISECONDS)
.toList()
.doOnError {
searchResultSubject.onNext(false)
logTo(log).warning("Timeout or error happens. %s", it)
}
.doOnSuccess {
searchResultSubject.onNext(true)
}
.onErrorReturn { emptyList() }
.blockingGet()
}
results.values = found
results.count = found.size
return results
}
@MainThread
override fun publishResults(constraint: CharSequence?, results: Filter.FilterResults) {
logTo(log).info("publishing results. Found: %s items", results.count)
data.clear()
val list = results.values as? List<*>
list?.let {
val values = it.filterIsInstance<PlaceData>()
if (values.isNotEmpty()) {
data.addAll(values)
notifyDataSetChanged()
}
}
}
}
private fun fetchAutocompletePredictions(query: String, latLngBounds: LatLngBounds): Observable<PlaceData> {
Timber.d("places api request: %s (total: %s, cached: %s)", query, PlacesApiCache.CALLS.incrementAndGet(), PlacesApiCache.HITS.get())
val rectangularBounds = toRectangularBounds(latLngBounds)
val request = FindAutocompletePredictionsRequest.builder()
.setLocationBias(rectangularBounds)
.setQuery(query)
.build()
return Observable.create {
placesClient.findAutocompletePredictions(request).addOnSuccessListener { response ->
val predictions = response.autocompletePredictions
val results = mutableListOf<PlaceData>()
for (i in 0 until Math.min(predictions.size, MAX_RESULTS)) {
results.add(placeDataFrom(predictions[i]))
}
PlacesApiCache.cacheData(query, results)
for (result in results) {
it.onNext(result)
}
it.onComplete()
}.addOnFailureListener { exception ->
if (exception is ApiException) {
Timber.e("Place not found: %s", exception.getStatusCode())
}
it.onError(exception)
}
}
}
私有内部类自动完成过滤器:过滤器(){
@工作线程
重写性能筛选(约束:CharSequence?):Filter.FilterResults{
val results=Filter.FilterResults()
val搜索=约束?.toString()?:“”
var found=emptyList()
//空搜索的快速回复
val bounds=latLngBounds
如果(!TextUtils.isEmpty(搜索)&&bounds!=null){
found=placesApiHelper.fetchAutocompletePredictions(搜索,边界)
.超时(1000L,时间单位为毫秒)
托利斯先生()
杜恩先生{
SearchResultsObject.onNext(false)
logTo(log)。警告(“发生超时或错误。%s”,it)
}
杜恩塞斯先生{
SearchResultsObject.onNext(true)
}
.onErrorReturn{emptyList()}
.blockingGet()
}
results.values=找到
results.count=found.size
返回结果
}
@主线
重写fun publishResults(约束:CharSequence?,结果:Filter.FilterResults){
logTo(log.info)(“发布结果。找到:%s个项目”,结果。计数)
data.clear()
val list=结果。值为?列表
名单?让我看看{
val values=it.filterIsInstance()
if(values.isNotEmpty()){
data.addAll(值)
notifyDataSetChanged()
}
}
}
}
fetchAutoCompletePredictions()如下所示:
private inner class AutocompleteFilter : Filter() {
@WorkerThread
override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
val results = Filter.FilterResults()
val search = constraint?.toString() ?: ""
var found = emptyList<PlaceData>()
// quick reply on empty search
val bounds = latLngBounds
if (!TextUtils.isEmpty(search) && bounds != null) {
found = placesApiHelper.fetchAutocompletePredictions(search, bounds)
.timeout(1000L, TimeUnit.MILLISECONDS)
.toList()
.doOnError {
searchResultSubject.onNext(false)
logTo(log).warning("Timeout or error happens. %s", it)
}
.doOnSuccess {
searchResultSubject.onNext(true)
}
.onErrorReturn { emptyList() }
.blockingGet()
}
results.values = found
results.count = found.size
return results
}
@MainThread
override fun publishResults(constraint: CharSequence?, results: Filter.FilterResults) {
logTo(log).info("publishing results. Found: %s items", results.count)
data.clear()
val list = results.values as? List<*>
list?.let {
val values = it.filterIsInstance<PlaceData>()
if (values.isNotEmpty()) {
data.addAll(values)
notifyDataSetChanged()
}
}
}
}
private fun fetchAutocompletePredictions(query: String, latLngBounds: LatLngBounds): Observable<PlaceData> {
Timber.d("places api request: %s (total: %s, cached: %s)", query, PlacesApiCache.CALLS.incrementAndGet(), PlacesApiCache.HITS.get())
val rectangularBounds = toRectangularBounds(latLngBounds)
val request = FindAutocompletePredictionsRequest.builder()
.setLocationBias(rectangularBounds)
.setQuery(query)
.build()
return Observable.create {
placesClient.findAutocompletePredictions(request).addOnSuccessListener { response ->
val predictions = response.autocompletePredictions
val results = mutableListOf<PlaceData>()
for (i in 0 until Math.min(predictions.size, MAX_RESULTS)) {
results.add(placeDataFrom(predictions[i]))
}
PlacesApiCache.cacheData(query, results)
for (result in results) {
it.onNext(result)
}
it.onComplete()
}.addOnFailureListener { exception ->
if (exception is ApiException) {
Timber.e("Place not found: %s", exception.getStatusCode())
}
it.onError(exception)
}
}
}
AutoCompletePredictions(查询:字符串,latLngBounds:latLngBounds):可观察{
Timber.d(“places api请求:%s(总数:%s,缓存:%s)”,查询,PlacesApiCache.CALLS.incrementAndGet(),PlacesApiCache.HITS.get()
val rectangularBounds=toRectangularBounds(latLngBounds)
val request=FindAutocompletePredictionsRequest.builder()
.setLocationBias(矩形边界)
.setQuery(查询)
.build()
返回可观察的。创建{
placesClient.FindAtoCompletePredictions(请求).addOnSuccessListener{response->
val预测=响应。自动完成预测
val results=mutableListOf()
对于(i在0中直到Math.min(predicts.size,MAX_结果)){
结果.添加(placeDataFrom(预测[i]))
}
PlacesApiCache.cacheData(查询、结果)
for(结果中的结果){
it.onNext(结果)
}
it.onComplete()
}.addOnFailureListener{异常->
如果(异常为ApiException){
Timber.e(“未找到位置:%s”,exception.getStatusCode())
}
it.onError(例外)
}
}
}
我试图使用PublichSubject(来自JakeWharton库的PublishRelay),但我仍然没有信心通过此调用(获取约束)修复它,因为事件在这里发生,同样的方法也应该返回FIlterResult。这意味着观察者也应该被置于performFiltering()中。这意味着对于每个字母条目,此方法都会命中多个观察者。而且,我应该使用与新的搜索任务(约束)相同的方法来调用subject.onNext() 在这种情况下,如何使用debounce运算符使整个过程同步,并在结束时返回FIlterResults
提前谢谢 我去掉了过滤器。我没有让过滤器回调得到关于新搜索字符串的通知,而是添加了我自己的publishSubject来观察新搜索字符串并通知观察者 Own observer(使用publicSubject而不是filter回调)允许我在流中插入debounce操作符 在适配器中添加了以下内容:
private var queryPlacesSubject = PublishSubject.create<String>()
init {
subscribeForPlacePredictions()
}
private fun subscribeForPlacePredictions() {
queryPlacesSubject
.debounce(DEBOUNCE_TIME_MILLIS, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.observeOn(Schedulers.newThread())
.doOnNext { findPlacePredictions(it) }
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {notifyThePlacesChanged()}
.subscribeOn(Schedulers.io())
.subscribe()
}
fun setQuery(query: String) {
queryPlacesSubject.onNext(query)
}
private fun findPlacePredictions(query: String?) {
val search = query ?: ""
// save entered text by user for highlight operations
highlight = search
// we should be in background thread already
var found = emptyList<PlaceData>()
// quick reply on empty search
val bounds = latLngBounds
if (!TextUtils.isEmpty(search) && bounds != null) {
found = placesApiHelper.requestAutocomplete(search, bounds)
.timeout(runtime.timeoutAutocompleteSearch(), TimeUnit.MILLISECONDS)
.toList()
.doOnError {
searchResultSubject.onNext(false)
logTo(log).warning("Timeout or error happens. %s", it)
}
.doOnSuccess {
searchResultSubject.onNext(true)
}
.onErrorReturn { emptyList() }
.blockingGet()
}
data.clear()
data.addAll(found)
}
private fun notifyThePlacesChanged() {
notifyDataSetChanged()
}
我去掉了过滤器。我没有让过滤器回调得到关于新搜索字符串的通知,而是添加了我自己的publishSubject来观察新搜索字符串并通知观察者 Own observer(使用publicSubject而不是filter回调)允许我在流中插入debounce操作符 在适配器中添加了以下内容:
private var queryPlacesSubject = PublishSubject.create<String>()
init {
subscribeForPlacePredictions()
}
private fun subscribeForPlacePredictions() {
queryPlacesSubject
.debounce(DEBOUNCE_TIME_MILLIS, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.observeOn(Schedulers.newThread())
.doOnNext { findPlacePredictions(it) }
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {notifyThePlacesChanged()}
.subscribeOn(Schedulers.io())
.subscribe()
}
fun setQuery(query: String) {
queryPlacesSubject.onNext(query)
}
private fun findPlacePredictions(query: String?) {
val search = query ?: ""
// save entered text by user for highlight operations
highlight = search
// we should be in background thread already
var found = emptyList<PlaceData>()
// quick reply on empty search
val bounds = latLngBounds
if (!TextUtils.isEmpty(search) && bounds != null) {
found = placesApiHelper.requestAutocomplete(search, bounds)
.timeout(runtime.timeoutAutocompleteSearch(), TimeUnit.MILLISECONDS)
.toList()
.doOnError {
searchResultSubject.onNext(false)
logTo(log).warning("Timeout or error happens. %s", it)
}
.doOnSuccess {
searchResultSubject.onNext(true)
}
.onErrorReturn { emptyList() }
.blockingGet()
}
data.clear()
data.addAll(found)
}
private fun notifyThePlacesChanged() {
notifyDataSetChanged()
}
我希望Places API builder能够帮助消除公告,并为应用程序做这些事情。但事实并非如此。当然,他们为什么要鼓励。让应用程序调用API并增加成本。:)我希望Places API builder能够帮助消除公告,并为应用程序做这些事情。但事实并非如此。当然,他们为什么要鼓励。让应用程序调用API并增加成本。:)