この問題を読んだ後 例外の対処方法 とこの媒体 2019年のAndroidネットワーキング-Kotlinのコルーチンによるレトロフィット を作成できるBaseService
で構成されるソリューションを作成しました呼び出しを改造して、結果と例外を「チェーン」に転送します。
[〜#〜] api [〜#〜]
@GET("...")
suspend fun fetchMyObject(): Response<List<MyObject>>
BaseService
protected suspend fun <T : Any> apiCall(call: suspend () -> Response<T>): Result<T> {
val response: Response<T>
try {
response = call.invoke()
} catch (t: Throwable) {
return Result.Error(mapNetworkThrowable(t))
}
if (!response.isSuccessful) {
val responseErrorBody = response.errorBody()
if (responseErrorBody != null) {
//try to parse to a custom ErrorObject
...
return Result.Error...
}
return Result.Error(mapHttpThrowable(Exception(), response.raw().code, response.raw().message))
}
return Result.Success(response.body()!!)
}
ChildService
suspend fun fetchMyObject(): Result<List<MyObject>> {
return apiCall(call = { api.fetchMyObject() })
}
レポ
suspend fun myObjectList(): List<MyObject> {
return withContext(Dispatchers.IO) {
when (val result = service.fetchMyObject()) {
is Result.Success -> result.data
is Result.Error -> throw result.exception
}
}
}
注:例外または1種類の成功結果をスローする以上のものが必要になる場合があります。これらの状況を処理するために、これは私たちがそれを達成する方法です。
sealed class SomeApiResult<out T : Any> {
object Success : SomeApiResult<Unit>()
object NoAccount : SomeApiResult<Unit>()
sealed class Error(val exception: Exception) : SomeApiResult<Nothing>() {
class Generic(exception: Exception) : Error(exception)
class Error1(exception: Exception) : Error(exception)
class Error2(exception: Exception) : Error(exception)
class Error3(exception: Exception) : Error(exception)
}
}
そして、ViewModelで:
when (result: SomeApiResult) {
is SomeApiResult.Success -> {...}
is SomeApiResult.NoAccount -> {...}
is SomeApiResult.Error.Error1 -> {...}
is SomeApiResult.Error -> {/*all other*/...}
}
このアプローチの詳細 ここ 。
BaseViewModel
protected suspend fun <T : Any> safeCall(call: suspend () -> T): T? {
try {
return call()
} catch (e: Throwable) {
parseError(e)
}
return null
}
ChildViewModel
fun fetchMyObjectList() {
viewModelScope.launch {
safeCall(call = {
repo.myObjectList()
//update ui, etc..
})
}
}
ViewModel
(またはBaseViewModel
)は、例外を処理するレイヤーである必要があると思います。たとえば、トーストを表示したい場合、例外のタイプを無視したい場合、別の関数を呼び出した場合など、このレイヤーにはUI決定ロジックがあります。 ..
どう思いますか?
EDIT:このトピックで medium を作成しました
リポジトリで例外を処理し、封印されたクラスオブジェクトの形式で単一の応答をviewmodelに返すことをお勧めします。これをリポジトリに保持することで、リポジトリが単一の信頼できる情報源となり、コードがよりクリーンで読みやすくなります。