Skip to content

Commit

Permalink
API Error Handling (Connection, Request Timeout and Cancel) at Networ…
Browse files Browse the repository at this point in the history
…k layer done.

Propagated error status back to view via live data.
  • Loading branch information
WaheedNazir committed Jan 21, 2022
1 parent 66f7fab commit d406a0a
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 22 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity
android:name=".ui.countries.CountriesActivity"
android:exported="true"
android:label="@string/news_by_countries">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -28,6 +29,7 @@

<activity
android:name=".ui.news.NewsActivity"
android:exported="false"
android:label="@string/news" />
</application>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package com.kotlin.mvvm.repository.api.network


import androidx.lifecycle.LiveData
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Callback
import retrofit2.Response
import com.kotlin.mvvm.utils.ApiErrorHandling
import retrofit2.*
import java.lang.reflect.Type
import java.util.concurrent.atomic.AtomicBoolean

Expand All @@ -21,14 +19,11 @@ import java.util.concurrent.atomic.AtomicBoolean
class LiveDataCallAdapter<R>(private val responseType: Type) :
CallAdapter<R, LiveData<Resource<R>>> {

override fun responseType(): Type {
return responseType
}
override fun responseType(): Type = responseType

override fun adapt(call: Call<R>): LiveData<Resource<R>> {
return object : LiveData<Resource<R>>() {
internal var started = AtomicBoolean(false)

var started = AtomicBoolean(false)
override fun onActive() {
super.onActive()
if (started.compareAndSet(false, true)) {
Expand All @@ -38,7 +33,14 @@ class LiveDataCallAdapter<R>(private val responseType: Type) :
}

override fun onFailure(call: Call<R>, throwable: Throwable) {
postValue(Resource.error(throwable.message))
postValue(
Resource.error(
ApiErrorHandling.error(
throwable,
call.isCanceled
), if (throwable is HttpException) throwable.code() else 0
)
)
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ constructor(private val appExecutors: AppExecutors) {
shouldFetch(data) -> fetchFromNetwork(dbSource)
else -> {
result.addSource(dbSource) { newData ->
setValue(Resource.success(newData))
setValue(Resource.success(newData,result.value?.retrofitAPICode ?: 0))
}
}
}
Expand Down Expand Up @@ -75,14 +75,24 @@ constructor(private val appExecutors: AppExecutors) {
// otherwise we will get immediately last cached value,
// which may not be updated with latest results received from network.
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
setValue(
Resource.success(
newData,
result.value?.retrofitAPICode ?: 0
)
)
}
}
}
}
else -> {
result.addSource(dbSource) {
result.setValue(Resource.error(errorMessage))
result.setValue(
Resource.error(
errorMessage,
result.value?.retrofitAPICode ?: 0
)
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ abstract class NetworkResource<RequestType> @MainThread constructor() {
response?.apply {
when {
status.isSuccessful() -> setValue(this)
else -> setValue(Resource.error(errorMessage))
else -> setValue(
Resource.error(
errorMessage,
result.value?.retrofitAPICode ?: 0
)
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package com.kotlin.mvvm.repository.api.network
data class Resource<ResultType>(
var status: Status,
var data: ResultType? = null,
var retrofitAPICode: Int = 0,
var errorMessage: String? = null
) {

Expand All @@ -22,8 +23,8 @@ data class Resource<ResultType>(
* last value is null so passing it optionally
*
*/
fun <ResultType> success(data: ResultType): Resource<ResultType> =
Resource(Status.SUCCESS, data)
fun <ResultType> success(data: ResultType, retrofitAPICode: Int): Resource<ResultType> =
Resource(Status.SUCCESS, data, retrofitAPICode = retrofitAPICode)

/**
* Creates [Resource] object with `LOADING` status to notify
Expand All @@ -37,8 +38,8 @@ data class Resource<ResultType>(
* Creates [Resource] object with `ERROR` status and [message].
* Returning object of Resource(Status.ERROR, errorMessage = message)
*/
fun <ResultType> error(message: String?): Resource<ResultType> =
Resource(Status.ERROR, errorMessage = message)
fun <ResultType> error(message: String?, retrofitAPICode: Int): Resource<ResultType> =
Resource(Status.ERROR, errorMessage = message, retrofitAPICode = retrofitAPICode)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ fun <ResultType> Response<ResultType>.toResource(): Resource<ResultType> {
isSuccessful -> {
val body = body()
when {
body != null -> Resource.success(body)
else -> Resource.error(error)
body != null -> Resource.success(body, this.code())
else -> Resource.error(error, this.code())
}
}
else -> Resource.error(error)
else -> Resource.error(error, this.code())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import java.lang.Exception
import java.net.SocketTimeoutException


object CallAdapterErrorHandling {
object ApiErrorHandling {

private const val ERROR_SOMETHING_WENT_WRONG = "Something went wrong."
private const val ERROR_REQUEST_CANCELLED = "Request cancelled."
Expand Down

0 comments on commit d406a0a

Please sign in to comment.