android - Kotlin 协程处理错误和实现

标签 android kotlin kotlin-coroutines coroutine

第一次使用协程。需要帮助。

这是我的流程:

Presenter 想要登录所以调用 Repository Interface。 Repository 实现 RepositoryInterface。 所以 Repository 调用 APIInterface。 APIInterface由APIInterfaceImpl实现。 APIInterfaceImpl 最后调用MyRetrofitInterface。

这是流程图:

Presenter -> Repository -> APIInterfaceImpl -> MyRetrofitInterface

一旦我收到登录响应:

APIInterfaceImpl -> Repository -> 将数据存储在缓存中 -> 将 http 状态代码提供给 Presenter

这是我的代码:

存储库接口(interface).kt

fun onUserLogin(loginRequest: LoginRequest): LoginResponse

存储库.kt

class Repository : RepositoryInterface {
   private var apiInterface: APIInterface? = null

   override fun onUserLogin(loginRequest: LoginRequest): LoginResponse {
         return apiInterface?.makeLoginCall(loginRequest)
   }
}

API接口(interface).kt

suspend fun makeLoginCall(loginRequest): LoginResponse?

APIInterfaceImpl.kt

override suspend fun makeLoginCall(loginRequest: LoginRequest): LoginResponse? {
        if (isInternetPresent(context)) {
            try {
                val response = MyRetrofitInterface?.loginRequest(loginRequest)?.await()
                return response
            } catch (e: Exception) {
                //How do i return a status code here
            }
        } else {
        //How do i return no internet here
            return Exception(Constants.NO_INTERNET)
        }
}

MyRetrofitInterface.kt

@POST("login/....")
fun loginRequest(@Body loginRequest: LoginRequest): Deferred<LoginResponse>?

我的问题是:

  1. 我的方法在架构上是否正确?
  2. 如何在我的代码中传递 http 错误代码或没有互联网连接
  3. 我的解决方案还有更好的方法吗?

最佳答案

在本地范围内启动协程是一个很好的做法,它可以在生命周期感知类中实现,例如 PresenterViewModel。您可以使用下一种方法来传递数据:

  1. 在单独的文件中创建 sealed Result 类及其继承者:

    sealed class Result<out T : Any>
    class Success<out T : Any>(val data: T) : Result<T>()
    class Error(val exception: Throwable, val message: String = exception.localizedMessage) : Result<Nothing>()
    
  2. 使 onUserLogin 函数可挂起并在 RepositoryInterfaceRepository 中返回 Result:

    suspend fun onUserLogin(loginRequest: LoginRequest): Result<LoginResponse> {
        return apiInterface.makeLoginCall(loginRequest)
    }
    
  3. APIInterfaceAPIInterfaceImpl中的makeLoginCall函数修改为如下代码:

    suspend fun makeLoginCall(loginRequest: LoginRequest): Result<LoginResponse> {
        if (isInternetPresent()) {
            try {
                val response = MyRetrofitInterface?.loginRequest(loginRequest)?.await()
                return Success(response)
            } catch (e: Exception) {
                return Error(e)
            }
        } else {
            return Error(Exception(Constants.NO_INTERNET))
        }
    }
    
  4. 为您的Presenter 使用下一个代码:

    class Presenter(private val repo: RepositoryInterface,
                    private val uiContext: CoroutineContext = Dispatchers.Main
    ) : CoroutineScope { // creating local scope
    
        private var job: Job = Job()
    
        // To use Dispatchers.Main (CoroutineDispatcher - runs and schedules coroutines) in Android add
        // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
        override val coroutineContext: CoroutineContext
            get() = uiContext + job
    
        fun detachView() {
            // cancel the job when view is detached
            job.cancel()
        }
    
        fun login() = launch { // launching a coroutine
            val request = LoginRequest()
            val result = repo.onUserLogin(request) // onUserLogin() function isn't blocking the Main Thread
    
            //use result, make UI updates
            when (result) {
                is Success<LoginResponse> -> { /* update UI when login success */ } 
                is Error -> { /* update UI when login error */ }
            }
        }
    }
    

编辑

我们可以在 Result 类上使用扩展函数来替换 when 表达式:

inline fun <T : Any> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
    if (this is Success) action(data)
    return this
}
inline fun <T : Any> Result<T>.onError(action: (Error) -> Unit): Result<T> {
    if (this is Error) action(this)
    return this
}

class Presenter(...) : CoroutineScope {

    // ...

    fun login() = launch {
        val request = LoginRequest()
        val result = repo.onUserLogin(request) 

        result
            .onSuccess {/* update UI when login success */ }
            .onError { /* update UI when login error */ }
    }
}

关于android - Kotlin 协程处理错误和实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54077592/

相关文章:

java - 文本是否包含日期格式?

android - `suspendCoroutine`抛出`This job has not completed yet`异常?

kotlin - 当您的所有协程已经用 CouroutineExceptionHandler 包装时,如何发现 "Job was cancelled"异常的来源?

android - 异步任务内存泄漏

android - 在 gmail-api 中获取发件人邮件

spring-boot - Spring-Boot 是否处理 WebFlux 上下文之外的 Kotlin 协程?

android - 完成 Kotlin 中的异步调用列表

android - actionbar setnavigationmode 弃用

android - 如何在android中的内存游戏中提供动画?

Kotlin:本地函数是否作为内联参数传递给内联函数?