-
Notifications
You must be signed in to change notification settings - Fork 441
/
TimeoutAndRetryCallbackViewModel.kt
179 lines (150 loc) · 5.99 KB
/
TimeoutAndRetryCallbackViewModel.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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()
}
}