I want to call 2 retrofit services in parallel and then do an action only when both of them finished, but I don't seem to figuer it out how.
I have a viewModel where I have defined my services:
var config= List<Configuration>
fun getClientProducts() {
getClientClientConfigUseCase
.build(this)
.executeWithError({ config ->
config = config
}, {
})
}
var therapies = List<DtoTherapy>
fun getTherapies() {
getTherapiesUseCase
.build(this)
.executeWithError({ config ->
therapies = it
}, {
})
}
And then I want to call both services in parallel in my fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupUi(view)
loadUserData()
viewModel.getClientProducts()
viewModel.getTherapies()
}
And when both variables config and therapies have the value do an action. But as I said maybe one service take 1 sec to respond and another 4 secs, and I want only to perfom an action when both have finished. Any help with be appreciated.
Here is the class I use to build the use case call:
abstract class SingleUseCase<T> : UseCase() {
private lateinit var single: Single<T>
private lateinit var useCaseInterface: UseCaseInterface
private var withLoader: Boolean = false
private var withErrorMessage: Boolean = false
internal abstract fun buildUseCaseSingle(): Single<T>
fun build(useCaseInterface: UseCaseInterface): SingleUseCase<T> {
this.withLoader = false
this.withErrorMessage = false
this.useCaseInterface = useCaseInterface
this.single = buildUseCaseSingle()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doAfterSuccess { useCaseInterface.onSuccess(it) }
return this
}
fun withLoader(): SingleUseCase<T> {
this.withLoader = true
return this
}
fun withErrorMessage(): SingleUseCase<T> {
this.withErrorMessage = true
return this
}
fun single(): Single<T> {
return this.single
}
fun execute(onSuccess: ((t: T) -> Unit)) {
useCaseInterface.onPrepareRequest(withLoader)
buildObservable(onSuccess)
}
private fun buildObservable(onSuccess: ((t: T) -> Unit)) {
disposeLast()
lastDisposable = single
.doFinally { useCaseInterface.onFinishRequest(this.withLoader) }
.subscribe(
{ onSuccess(it) },
{
useCaseInterface.onError(mapError(it), withErrorMessage)
})
lastDisposable?.let {
compositeDisposable.add(it)
}
}
fun executeWithError(onSuccess: ((success: T) -> Unit), onError: ((error: ApiError ) -> Unit)) {
useCaseInterface.onPrepareRequest(withLoader)
buildObservable(onSuccess, onError)
}
private fun buildObservable(onSuccess: ((success: T) -> Unit), onError: ((error: ApiError ) -> Unit)) {
disposeLast()
lastDisposable = single
.doFinally { useCaseInterface.onFinishRequest(this.withLoader) }
.subscribe(
{ onSuccess(it) },
{
onError(mapError(it))
useCaseInterface.onError(mapError(it), withErrorMessage)
})
lastDisposable?.let {
compositeDisposable.add(it)
}
}
private fun mapError(t: Throwable): ApiError {
return if(t is HttpException) {
val apiError = t.response()?.errorBody()?.string()
try {
ApiError (t.code(), t.response()?.errorBody()?.string(), Gson().fromJson(apiError, GenericError::class.java))
} catch(e: Exception) {
ApiError (-2, "Unkown error")
}
} else ApiError (-1, "Unkown error")
}
}
And this is a specific usecase class:
class GetClientConfigUseCase @Inject constructor(private val repository: UserRepository) :
SingleUseCase<ClientConfigResponse>() {
override fun buildUseCaseSingle(): Single<ClientConfigResponse> {
return repository.getUserConfig()
}
}