Правильное использование сопрограмм - PullRequest
0 голосов
/ 14 января 2019

Я впервые использую сопрограмму. Я следую шаблону MVP для простого приложения входа в систему. Вот мой поток кода -

Нажатая кнопка входа будет следовать этому направлению -

LoginFragment -> LoginPresenter -> Репозиторий -> APIRepository -> RetrofitInterface

Ответ при входе будет следовать в этом направлении -

RetrofitInterface -> APIRepository -> Репозиторий -> LoginPresenter -> LoginFragment

Вот код -

RetrofitInterface.kt

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

Вот мой Результат.kt

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>()
}

APIRepository.kt

override suspend fun loginAPICall(loginRequest: LoginRequest) : Result<LoginResponse>? {
        try {
            val loginResponse = apiInterface?.loginAPI(loginRequest)?.await()
            return Result.Success<LoginResponse>(loginResponse!!)
        } catch (e : HttpException) {
            return Result.Error(e)
        } catch (e : Throwable) {
            return Result.Error(e)
        }
    }

Repository.kt

override suspend fun loginUser(loginRequest: LoginRequest): Result<LoginResponse> {
        if (isInternetPresent(context)) {
            val result = apiRepositoryInterface?.loginAPICall(loginRequest)
            if (result is Result.Success<LoginResponse>) {
                val loginData = result.data
                cache?.storeData(loginData)
            }
            return result!!
        } else {
            return Result.Error(Exception())
        }
    }

Как мне запустить сопрограмму сейчас в моем докладчике? Мне нужно выполнить этот вызов API в фоновом потоке и опубликовать результаты в потоке пользовательского интерфейса?

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Вам необходимо запустить сопрограмму в Presenter с использованием локальной области действия и ввести CoroutineContext, чтобы иметь возможность изменить его, например, в модульных тестах:

class Presenter(private val repo: Repository,
            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 dependency: 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(request: LoginRequest) = launch { // launching a coroutine
        val result = repo.loginUser(request) // calling 'loginUser' function will not block the Main Thread, it suspends the coroutine

        //use result, update UI
        when (result) {
            is Success<LoginResponse> -> { /* update UI when login success */ } 
            is Error -> { /* update UI when login error */ }
        }
    }
}
0 голосов
/ 14 января 2019

вы можете использовать сопрограмму таким образом

  private var parentJob = Job()

    private val coroutineContext: CoroutineContext
        get() = parentJob + Dispatchers.Main

    private val scope = CoroutineScope(coroutineContext)



 scope.launch(Dispatchers.IO) {

     // your api call 

 }

Вы можете позвонить parentJob.cancel() после выполнения работы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...