Clean Architecture

Introducción

En esta parte vamos a hablar sobre el módulo encargado de realizar parte de nuestra lógica y pasar parte a nuestra capa de data. Esta capa es la de los interactors (o casos de uso) que se encuentra dentro de nuestro Domain.

Recordemos un poco el esquema que utilizamos para definir nuestra arquitectura.

mvp clean

Como podemos ver , en nuestra capa de dominio, es donde vamos a tener nuestra lógica de negocio conectada con los casos de uso, es decir, vamos tener una interfaz con el caso de uso que realiza la acción en nuestro dominio y la logica de negocio conectada a el mismo.

Esta lógica de negocio puede usar parte de la capa de Data para guardar información tanto en la nube como localmente, esto lo hacemos con el patron Repositorio.

Interactor

Básicamente son casos de usos encargados de realizar nuestra lógica de negocio, estos casos de usos o interactors son llamados desde nuestro Presenter con el objetivo de hacer mas independiente y mas estructurada nuestra aplicación.

Al mismo tiempo, si estos interactors necesitaran de guardar datos, llamarian a su repositorio en la capa Data, haciendo asi, una abstracción mas a nuestro modelo, para poder dividir las preocupaciones en mas partes y hacer los modulos lo mas independientes posible, cumpliendo con el principio de responsabilidad única (single responsibility principle).

LoginPresenter.kt

override fun signInUserWithEmailAndPassword(email: String, password: String) {
    view?.showProgressBar()
    signInInteractor?.signInWithEmailAndPassword(email,password,object: SignInInteractor.SigninCallback{

        override fun onSignInSuccess() {
            if(isViewAttached()){
                view?.hideProgressBar()
                view?.navigateToMain()
            }
        }

        override fun onSignInFailure(errorMsg: String) {
            if(isViewAttached()){
                view?.hideProgressBar()
                view?.showError(errorMsg)
            }
        }
    })

}

Haciendo el llamado a signInInteractor?.signInWithEmailAndPassword(...) estamos llamando al metodo signInWithEmailAndPassword que se encuentra en nuestra capa de dominio, dentro de nuestro SignInInteractorImpl.kt

La llamada a este método devuelve una respuesta por el callback que se encuentra en SignInInteractor.SigninCallback , por lo que podemos obtener un onSignInSuccess() o un onSignInFailure(errorMsg: String), que con los cuales, podemos actualizar nuestra vista.

La interfaz solo va a tener los métodos (casos de uso) que se deberia ejecutar para realizar nuestra lógica de negocio.

SignInInteractor.kt

interface SignInInteractor {

    interface SigninCallback{
        fun onSignInSuccess()
        fun onSignInFailure(errorMsg:String)
    }

    fun signInWithEmailAndPassword(email:String,password:String,listener:SigninCallback)
}

Por último, implementamos nuestra interfaz dentro de nuestro SignInInteractorImpl.kt y realizamos la lógica para loguear a nuestro usuario, el cual ejecutara nuestro onSignInSuccess() callback, o de lo contrario onSignInFailure(errorMsg: String) si algún error sucedió mientras se estaba logueando nuestro usuario.

SignInInteractorImpl.kt

override fun signInWithEmailAndPassword(email: String, password: String,
    listener: SignInInteractor.SigninCallback) {

    FirebaseAuth.getInstance().signInWithEmailAndPassword(email,password).addOnCompleteListener {
        if(it.isSuccessful){
            listener.onSignInSuccess()
        }else{
            listener.onSignInFailure(it.exception?.message!!)
        }
    }

}

Video tutorial

Links útiles

Todo este código fuente y el proyecto entero se puede encontrar en GitHub