Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

207
Views
Las corrutinas de Kotlin manejan el error y la implementación.

Usando corrutinas por primera vez. Necesitas ayuda.

Aquí está mi flujo:

El presentador quiere iniciar sesión, por lo que llama a la interfaz del repositorio. El repositorio implementa RepositoryInterface. Entonces Repository llama APIInterface. APIInterface está implementado por APIInterfaceImpl. APIInterfaceImpl finalmente llama a MyRetrofitInterface.

Aquí está el flujo esquemáticamente:

Presentador -> Repositorio -> APIInterfaceImpl -> MyRetrofitInterface

Una vez que recibo la respuesta de inicio de sesión:

APIInterfaceImpl -> Repositorio -> Almacena los datos en caché -> Da el código de estado http al presentador

Aquí está mi código:

RepositoryInterface.kt

 fun onUserLogin(loginRequest: LoginRequest): LoginResponse

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

Mis preguntas son:

  1. ¿Es mi enfoque arquitectónicamente correcto?
  2. ¿Cómo paso códigos de error http o sin conexión a Internet en mi código?
  3. ¿Algún enfoque más agradable para mi solución?
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Es una buena práctica lanzar una rutina en un ámbito local que se pueda implementar en clases conscientes del ciclo de vida, por ejemplo, Presenter o ViewModel . Puede usar el siguiente enfoque para pasar datos:

  1. Cree la clase de Result sealed y sus herederos en un archivo separado:

     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. Haga que la función onUserLogin suspendible y devuelva el Result en RepositoryInterface y Repository :

     suspend fun onUserLogin(loginRequest: LoginRequest): Result<LoginResponse> { return apiInterface.makeLoginCall(loginRequest) }
  3. Cambie la función makeLoginCall en APIInterface y APIInterfaceImpl de acuerdo con el siguiente código:

     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. Use el siguiente código para su 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 */ } } } }

EDITAR

Podemos usar funciones de extensión en la clase Result para reemplazar la expresión 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 */ } } }
over 4 years ago · Santiago Trujillo Report

0

EDITAR:

Estoy probando esta solución en mi nueva aplicación y lancé que si ocurre un error en el método launchSafe y trato de volver a intentar la solicitud, el método launcSafe() no funciona correctamente. Así que cambié la lógica de esta manera y el problema está solucionado.

 fun CoroutineScope.launchSafe( onError: (Throwable) -> Unit = {}, onSuccess: suspend () -> Unit ) { launch { try { onSuccess() } catch (e: Exception) { onError(e) } } }

RESPUESTA ANTIGUA:

Pienso mucho sobre este tema y encontré una solución. Creo que esta solución es más limpia y fácil de manejar excepciones. En primer lugar, cuando use código de escritura como

 fun getNames() = launch { }

Está devolviendo la instancia de trabajo a la interfaz de usuario. Creo que esto no es correcto. Ui no debe tener referencia a la instancia de trabajo. Intenté la siguiente solución, funciona bien para mí. Pero quiero discutir si puede ocurrir algún efecto secundario. Agradezco ver sus comentarios.

 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() } }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!