首次使用协程。需要帮忙。

这是我的流程:

演示者要登录,因此调用存储库接口(interface)。存储库实现RepositoryInterface。
因此,存储库调用APIInterface。 APIInterface由APIInterfaceImpl实现。
APIInterfaceImpl最终调用MyRetrofitInterface。

这是图解的流程图:

演示者->存储库-> APIInterfaceImpl-> MyRetrofitInterface

获得登录响应后:

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

这是我的代码:

RepositoryInterface.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)
   }
}

APIInterface.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>?

我的问题是:
  • 我的方法在结构上正确吗?
  • 如何在我的代码
  • 中传递http错误代码或没有互联网连接
  • 我的解决方案还有更好的方法吗?
  • 最佳答案

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

  • 在单独的文件中创建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>()
    
  • 使onUserLogin函数可挂起,并在ResultRepositoryInterface中返回Repository:
    suspend fun onUserLogin(loginRequest: LoginRequest): Result<LoginResponse> {
        return apiInterface.makeLoginCall(loginRequest)
    }
    
  • 根据以下代码更改makeLoginCallAPIInterface中的APIInterfaceImpl函数:
    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))
        }
    }
    
  • 为您的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 */ }
        }
    }
    

    10-07 22:41