Reputation: 1
I have a call to google place autocomplete sdk on a Rxjava that brings me a list of AutoCompletePredictions and then I use that list to iterate and call the place details sdk of google with that I want to return a single list with all the places details but it doesnt triggers.
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()
}
Upvotes: 0
Views: 806
Reputation: 4002
Please provide a proper example next time. It is quite work intensive to mock your APIs.
import io.reactivex.rxjava3.core.Single import org.junit.jupiter.api.Test
This example will wrap the GoogleApi into a reactive
-API, which provides Single
functions. In order to collect all results in a List
, you could use Single.zip
.
Note: You should not use MutableList
with RxJava. Always use immutable data types, or you get into trouble.
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)
}
}
I did not add observeOn
and subscribeOn
, because it makes testing a little more difficulty. Please add it by yourself, at the end of the Single
form SearchApiImpl#search
Upvotes: 1