#java #android #kotlin #rx-java #rx-android
#java #Android #kotlin #rx-java #rx-android
Вопрос:
У меня есть вызов Google place autocomplete sdk на Rxjava, который выдает мне список автозаполнения, а затем я использую этот список для итерации и вызова sdk place details от Google, с помощью которого я хочу вернуть единый список со всеми деталями places, но он не срабатывает.
fun searchAutoComplete(word: String): Single<MutableList<SuggestedPlace>> {
if (placeClient == null) {
placeClient = this.context?.let { Places.createClient(it) }
}
return Observable.create<SuggestedPlace> { emiter ->
var request = GooglePlaceHelper.getPlacesSuggestions(word)
placeClient?.findAutocompletePredictions(request)
?.addOnSuccessListener { response: FindAutocompletePredictionsResponse ->
response.autocompletePredictions.forEach { place ->
var request = GooglePlaceHelper.getPlaceDetailRequest(place.placeId)
placeClient?.fetchPlace(request)
?.addOnSuccessListener { response: FetchPlaceResponse ->
val place = response.place
place?.let {
var suggestedPlace = SuggestedPlace(place.address!!, place.latLng?.latitude!!, place.latLng?.longitude!!)
emiter.onNext(suggestedPlace)
}
}
}
}
}.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).toList()
}
Комментарии:
1. Код выглядит так, что в нем много мусора здесь и там. Трудно понять, в чем проблема.
2. полностью согласен @AnimeshSahu
Ответ №1:
Пожалуйста, предоставьте правильный пример в следующий раз. Издеваться над вашими API-интерфейсами довольно трудоемко.
импортируйте io.reactivex.rxjava3.core.Одиночный импорт org.junit.jupiter.api.Test
В этом примере GoogleAPI будет преобразован в a reactive
-API, который предоставляет Single
функции. Чтобы собрать все результаты в a List
, вы могли бы использовать Single.zip
.
Примечание: вы не должны использовать MutableList
с RxJava. Всегда используйте неизменяемые типы данных, иначе у вас возникнут проблемы.
class So65684080 {
@Test
fun so65684080() {
val googleClientStub = GoogleClientStub()
val reactiveClient = GoogleClientReactiveImpl(googleClientStub)
val searchApiImpl = SearchApiImpl(reactiveClient)
searchApiImpl.search("whatever")
.test()
.assertValue(listOf(SuggestedPlace("fetchPlace"), SuggestedPlace("fetchPlace")))
}
}
internal interface SearchApi {
fun search(word: String): Single<List<SuggestedPlace>>
}
internal class SearchApiImpl(private val client: GoogleClientReactive) : SearchApi {
override fun search(word: String): Single<List<SuggestedPlace>> {
return client.findAutocompletePredictions("whatever")
.flatMap { resp ->
val fetches = resp.values.map { r -> client.fetchPlace(r) }
Single.zip(fetches) { arr ->
arr.map {
val fetchPlaceResponse = it as FetchPlaceResponse
SuggestedPlace(fetchPlaceResponse.name)
}
.toList()
}
}
}
}
internal interface GoogleClient {
fun findAutocompletePredictions(request: String): Result<FindAutocompletePredictionsResponse>
fun fetchPlace(request: String): Result<FetchPlaceResponse>
}
internal interface GoogleClientReactive {
fun findAutocompletePredictions(request: String): Single<FindAutocompletePredictionsResponse>
fun fetchPlace(request: String): Single<FetchPlaceResponse>
}
internal class GoogleClientStub : GoogleClient {
override fun findAutocompletePredictions(request: String): Result<FindAutocompletePredictionsResponse> {
return ResultStub<FindAutocompletePredictionsResponse>(FindAutocompletePredictionsResponse(listOf("fetch1", "fetch2")))
}
override fun fetchPlace(request: String): Result<FetchPlaceResponse> {
return ResultStub<FetchPlaceResponse>(FetchPlaceResponse("fetchPlace"))
}
}
internal class GoogleClientReactiveImpl(private val client: GoogleClient) : GoogleClientReactive {
override fun findAutocompletePredictions(request: String): Single<FindAutocompletePredictionsResponse> {
return Single.create { emitter ->
val response: (FindAutocompletePredictionsResponse) -> Unit = {
emitter.onSuccess(it)
}
client.findAutocompletePredictions(request).addOnSuccessListener(response)
// TODO: set emitter.setCancellable {} for unsubscribing
}
}
override fun fetchPlace(request: String): Single<FetchPlaceResponse> {
return Single.create { emitter ->
val response: (FetchPlaceResponse) -> Unit = {
emitter.onSuccess(it)
}
client.fetchPlace(request).addOnSuccessListener(response)
// TODO: set emitter.setCancellable {} for unsubscribing
}
}
}
internal data class SuggestedPlace(val name: String)
internal data class FetchPlaceResponse(val name: String)
internal data class FindAutocompletePredictionsResponse(val values: List<String>)
internal interface Result<T> {
fun addOnSuccessListener(response: (r: T) -> Unit)
}
internal class ResultStub<T>(val value: T) : Result<T> {
override fun addOnSuccessListener(response: (r: T) -> Unit) {
response(value)
}
}
Примечание
Я не добавлял observeOn
и subscribeOn
, потому что это немного усложняет тестирование. Пожалуйста, добавьте его самостоятельно в конце Single
формы SearchApiImpl#search