Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
340 views
in Technique[技术] by (71.8m points)

java - How can I return one list from Rxjava instead of multiple emitted singles?

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()

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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)
    }
}

Note

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

62 comments

56.6k users

...