Permalink
Cannot retrieve contributors at this time
Kotlin-Coroutine-Use-Cases-on-Android/app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/usecases/coroutines/usecase7/callbacks/TimeoutAndRetryCallbackViewModel.kt
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
179 lines (150 sloc)
5.99 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lukaslechner.coroutineusecasesonandroid.usecases.coroutines.usecase7.callbacks | |
import android.os.Handler | |
import android.os.Looper | |
import com.lukaslechner.coroutineusecasesonandroid.base.BaseViewModel | |
import com.lukaslechner.coroutineusecasesonandroid.mock.VersionFeatures | |
import retrofit2.Call | |
import retrofit2.Callback | |
import retrofit2.Response | |
import timber.log.Timber | |
class TimeoutAndRetryCallbackViewModel(api: CallbackMockApi = mockApi()) : | |
BaseViewModel<UiState>() { | |
private val totalAttempts = 3 | |
private var oreoFeaturesRequestAttemptNumber = 0 | |
private var pieFeaturesRequestAttemptNumber = 0 | |
private val shouldRetryOreoFeaturesRequest: Boolean | |
get() = oreoFeaturesRequestAttemptNumber < totalAttempts | |
private val shouldRetryPieFeaturesRequest: Boolean | |
get() = pieFeaturesRequestAttemptNumber < totalAttempts | |
private val timeout = 1000L | |
private val oreoFeaturesTimeoutHandler = Handler(Looper.getMainLooper()) | |
private val pieFeaturesTimeoutHandler = Handler(Looper.getMainLooper()) | |
private var oreoFeaturesCall = api.getAndroidVersionFeatures(27) | |
private var pieFeaturesCall = api.getAndroidVersionFeatures(28) | |
private var oreoFeaturesResult: VersionFeatures? = null | |
private var pieFeaturesResult: VersionFeatures? = null | |
private val oreoFeaturesReceived: Boolean | |
get() = oreoFeaturesResult != null | |
private val pieFeaturesReceived: Boolean | |
get() = pieFeaturesResult != null | |
fun performNetworkRequest() { | |
uiState.value = UiState.Loading | |
getOreoFeatures() | |
getPieFeatures() | |
} | |
private fun getOreoFeatures() { | |
oreoFeaturesRequestAttemptNumber++ | |
Timber.d("Start get oreo features request") | |
oreoFeaturesCall = oreoFeaturesCall.clone() | |
oreoFeaturesCall.enqueue(object : Callback<VersionFeatures> { | |
override fun onFailure(call: Call<VersionFeatures>, t: Throwable) { | |
Timber.e("Get oreo features onFailure() entered: $t") | |
stopOreoFeaturesTimeoutHandler() | |
postErrorOrRetryGetOreoFeatures() | |
} | |
override fun onResponse( | |
call: Call<VersionFeatures>, | |
response: Response<VersionFeatures> | |
) { | |
stopOreoFeaturesTimeoutHandler() | |
if (!response.isSuccessful) { | |
Timber.e("Get oreo features request was unsuccessful") | |
postErrorOrRetryGetOreoFeatures() | |
return | |
} else { | |
Timber.d("successful oreo response received.") | |
} | |
oreoFeaturesResult = response.body() | |
maybeNotifyView() | |
} | |
}) | |
setOreoFeaturesTimeout() | |
} | |
private fun setOreoFeaturesTimeout() { | |
val retryRunnable = Runnable { | |
Timber.e("Timeout for getting oreo features") | |
if (!oreoFeaturesReceived) { | |
oreoFeaturesCall.cancel() | |
} | |
} | |
Timber.d("start oreo Features Timeout Handler") | |
oreoFeaturesTimeoutHandler.postDelayed(retryRunnable, timeout) | |
} | |
private fun postErrorOrRetryGetOreoFeatures() { | |
if (shouldRetryOreoFeaturesRequest) { | |
getOreoFeatures() | |
} else { | |
uiState.value = UiState.Error("Network Request failed.") | |
cancelNetworkRequests() | |
} | |
} | |
private fun getPieFeatures() { | |
pieFeaturesRequestAttemptNumber++ | |
Timber.d("Start get pie features request") | |
pieFeaturesCall = pieFeaturesCall.clone() | |
pieFeaturesCall.enqueue(object : Callback<VersionFeatures> { | |
override fun onFailure(call: Call<VersionFeatures>, t: Throwable) { | |
Timber.e("Get pie features onFailure() entered: $t") | |
stopPieFeaturesTimeoutHandler() | |
postErrorOrRetryGetPieFeatures() | |
} | |
override fun onResponse( | |
call: Call<VersionFeatures>, | |
response: Response<VersionFeatures> | |
) { | |
stopPieFeaturesTimeoutHandler() | |
if (!response.isSuccessful) { | |
Timber.e("Get pie features request was unsuccessful") | |
postErrorOrRetryGetPieFeatures() | |
return | |
} else { | |
Timber.d("successful pie response received.") | |
} | |
pieFeaturesResult = response.body() | |
maybeNotifyView() | |
} | |
}) | |
setPieFeaturesTimeout() | |
} | |
private fun stopPieFeaturesTimeoutHandler() { | |
Timber.d("stopping pie Features Timeout Handler") | |
pieFeaturesTimeoutHandler.removeCallbacksAndMessages(null) | |
} | |
private fun setPieFeaturesTimeout() { | |
val retryRunnable = Runnable { | |
Timber.e("Timeout for getting pie features") | |
if (!pieFeaturesReceived) { | |
pieFeaturesCall.cancel() | |
} | |
} | |
Timber.d("start pie Features Timeout Handler") | |
pieFeaturesTimeoutHandler.postDelayed(retryRunnable, timeout) | |
} | |
private fun postErrorOrRetryGetPieFeatures() { | |
if (shouldRetryPieFeaturesRequest) { | |
getPieFeatures() | |
} else { | |
uiState.value = UiState.Error("Network Request failed.") | |
cancelNetworkRequests() | |
} | |
} | |
private fun maybeNotifyView() { | |
if (oreoFeaturesReceived && pieFeaturesReceived) { | |
uiState.value = UiState.Success(listOf(oreoFeaturesResult!!, pieFeaturesResult!!)) | |
} | |
} | |
override fun onCleared() { | |
super.onCleared() | |
cancelNetworkRequests() | |
stopOreoFeaturesTimeoutHandler() | |
stopPieFeaturesTimeoutHandler() | |
} | |
private fun stopOreoFeaturesTimeoutHandler() { | |
Timber.d("stopping oreo Features Timeout Handler") | |
oreoFeaturesTimeoutHandler.removeCallbacksAndMessages(null) | |
} | |
private fun cancelNetworkRequests() { | |
oreoFeaturesCall.cancel() | |
pieFeaturesCall.cancel() | |
} | |
} |