Сопрограммы Kotlin обрабатывают ошибки и реализацию - PullRequest
0 голосов
/ 07 января 2019

Использование сопрограмм в первый раз. Нужна помощь.

Вот мой поток:

Presenter хочет войти, поэтому вызывает интерфейс репозитория. Репозиторий реализует RepositoryInterface. Итак, репозиторий вызывает APIInterface. APIInterface реализуется с помощью APIInterfaceImpl. Наконец, APIInterfaceImpl вызывает MyRetrofitInterface.

Вот схема потока:

Presenter -> Repository -> APIInterfaceImpl -> MyRetrofitInterface

Как только я получу ответ на логин:

APIInterfaceImpl -> Репозиторий -> Сохраняет данные в кеше -> Предоставляет код состояния http для Presenter

Вот мой код:

RepositoryInterface.kt

fun onUserLogin(loginRequest: LoginRequest): LoginResponse

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

Мои вопросы:

  1. Правильно ли подходит мой подход?
  2. Как передать коды ошибок http или нет интернет-соединения в моем коде
  3. Есть более хороший подход к моему решению?

Ответы [ 2 ]

0 голосов
/ 29 марта 2019

Я много думаю об этой теме и пришел с решением. Я думаю, что это решение чище и легко обрабатывать исключения. Прежде всего, когда вы пишете код типа

fun getNames() = launch { }  

Вы возвращаете экземпляр задания в пользовательский интерфейс, я думаю, что это неправильно. Ui не должен иметь ссылку на экземпляр работы. Я попробовал ниже решение, это работает хорошо для меня. Но я хочу обсудить, может ли возникнуть побочный эффект. Благодарим Вас за комментарии.

fun main() {


    Presenter().getNames()

    Thread.sleep(1000000)

}


class Presenter(private val repository: Repository = Repository()) : CoroutineScope {

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Default // Can be Dispatchers.Main in Android

    fun getNames() = launchSafe(::handleLoginError) {
        println(repository.getNames())
    }


    private fun handleLoginError(throwable: Throwable) {
        println(throwable)
    }

    fun detach() = this.cancel()

}

class Repository {

    suspend fun getNames() = suspendCancellableCoroutine<List<String>> {
        val timer = Timer()

        it.invokeOnCancellation {
            timer.cancel()
        }

        timer.schedule(timerTask {
            it.resumeWithException(IllegalArgumentException())
            //it.resume(listOf("a", "b", "c", "d"))
        }, 500)
    }
}


fun CoroutineScope.launchSafe(
    onError: (Throwable) -> Unit = {},
    onSuccess: suspend () -> Unit
) {
    val handler = CoroutineExceptionHandler { _, throwable ->
        onError(throwable)
    }

    launch(handler) {
        onSuccess()
    }
}
0 голосов
/ 07 января 2019

Хорошей практикой является запуск сопрограммы в локальной области, которая может быть реализована в классах, поддерживающих жизненный цикл, например Presenter или ViewModel . Вы можете использовать следующий подход для передачи данных:

  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 приостановленной и вернуть Result в RepositoryInterface и Repository:

    suspend fun onUserLogin(loginRequest: LoginRequest): Result<LoginResponse> {
        return apiInterface.makeLoginCall(loginRequest)
    }
    
  3. Измените функцию makeLoginCall в APIInterface и 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))
        }
    }
    
  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 */ }
            }
        }
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...