>

Architecture Components: Repository y DataSources #AndroidMeetsKotlin

Francisco Manuel López Jurado     Colaboraciones    07/03/2019


Siguiendo con todo lo descrito en el anterior post que abordaba la implementación de LiveData y ViewModel en el patrón MVVM, ahora vas a conocer cuál es la función de un Repositorio y cómo proporciona los datos a los ViewModel y éstos a su vez a la vista. Sin más, ¡A por ello!

Capa a definir

Como puedes ver en la imagen anterior, el Repositorio será una capa que abstrae a los ViewModel del origen de los datos. Esta separación de responsabilidad proporciona una mejor trazabilidad ante posibles errores, mejora la posible escalabilidad de tu aplicación y la adaptación a cambios estructurales o de implementación. De esta forma, el ViewModel sólo se preocupa de solicitar el listado de elementos y es el repositorio el que toma la decisión de proporcionarselo desde los distintos orígenes de datos que tenga (internet, cache, local, sharedPreferences, etc).

Es importante destacar que se debería tener un repositorio y sus distintos data source por cada grupo de datos que tenga la app. Además, cada ViewModel debe estar asociado a una Activity ya que de esta forma separamos responsabilidades y mantenemos los indicado en Android Developers. En el caso del repositorio, varios ViewModel pueden nutrirse del mismo repositorio.

En cuanto a la implementación, vas a tomar como referencia el proyecto que hiciste en el anterior post y vamos a implementar esta capa a partir de él. El código de este post puedes encontrarlo en la rama “repository” del proyecto. Antes de ver la implementación del repositorio, debes ver qué es un DataSource y su implementación.

DataSource

Se trata de un origen de datos del repositorio, en este caso tienes dos orígenes posibles:

A continuación, verás la implementación de los distintos DataSource.

GithubRepoLocalDataSource

Debes implementar dos métodos:

  • getGithubRepos(query: String): LiveData<List>. Accede al DAO de la BD y solicita los datos mediante una query de Room. Puesto que tiene una consulta con un “LIKE” es necesario añadirle el carácter “%” al inicio y final para realizar la consulta de forma correcta.

  • insert(list: List). Inserta los elementos en la BD en background.

El código lo puedes encontrar en el siguiente enlace.

GithubRepoApiDataSource

Debes implementar un único método:

  • getGithubRepos(query: String, success: (response: List) -> Unit, failure: (errorMessage: String) -> Unit). Realizará la llamada a servicios y retorna los datos correctos en la función “success” y un mensaje de error en la función “failure” si la llamada ha provocado un error.

El código lo puedes encontrar en el siguiente enlace.

Repositorio

Las variables que debes crear:

  • repoApiDataSource: GithubRepoApiDataSource. Debes inicializarlo con su constructor sin parámetros.
  • repoLocalCacheDataSource: GithubRepoLocalDataSource. Igual que el caso anterior.
  • isRequesting: Boolean. Debes inicializarlo a false.
  • errorLiveData: MutableLiveData. Inicializado con el constructor sin parámetros de MutableLiveData.

La lógica que vas a implementar en este repositorio realiza la llamada al servicio e inmediatamente retorna la consulta de la base de datos, de esta forma obtienes el LiveData proporcionado por Room. La consulta al servicio tienes que hacerla usando el DataSource de API y el de la BD con el DataSource de local.

Una vez que la llamada a servicio ha retornado los datos, debes insertarlos en la BD y esto hará que el LiveData asociado se actualice de forma automática. En caso de que la llamada falle, se incluirá la información en el LiveData de error para que se informe a la vista.

En cuanto a métodos, sólo tendrá uno:

  • searchRepos(query: String) : LiveData<List>.

La implementación del repositorio lo tienes en el siguiente enlace.

SearchRepoViewModel

Lo primero que debes hacer es extender de la clase ViewModel. Esta clase tendrá cuatro variables:

  • queryLiveData = MutableLiveData(). Almacenará los cambios de la consulta realizada al pulsar el botón de “Buscar”.
  • githubRepository: GithubRepository.
  • errorMessageLiveData: LiveData. Se encargará de proporcionar a la vista la información actualizada de los errores en el servicio.
  • githubReposListLiveData: LiveData<List>. Para inicializarlo debes hacer uso de la función Transformations.switchMap. Esta función recibe como parámetro un LiveData al que observará sus cambios con el fin de aplicar la función que recibe como su segundo parámetro. De esta forma conseguiremos que la vista no tenga que registrarse y desregistrarse ante cambios en la consulta a la base de datos.

Además, debes implementar dos métodos:

  • updateQuery(newQuery: String). Actualizará el LiveData llamado “queryLiveData” el cuál provocará que se llame a la función pasada en el método “switchMap”.
  • search(query: String): LiveData<List>. Llamará al método “searchRepos(query)” del repositorio para que realice la función de obtener los datos.

El código del ViewModel lo puedes encontrar en el siguiente enlace.

MainActivity

Por último, sólo debes observar los LiveData del ViewModel desde la vista.

De esta forma, al pulsar sobre el botón de “Buscar” se realizará la llamada y se mostrará en un Toast el número de elementos.

Finalmente, en este post has visto una primera aproximación de cómo implementar un patrón repositorio utilizando componentes de Android Architecture Components con un patrón MVVM. En el siguiente post implementarás una paginación de este servicio, haremos usos de la librería Paging Library y verás qué puede aportar y cómo puede simplificar la paginación en tu aplicación. El código de este proyecto puedes encontrarlo en el siguiente enlace bajo la rama “repository”.


Sobre el autor

Francisco Manuel López Jurado   

Apasionado de la tecnología y todo lo que la rodea. Desarrollador Senior Android e iOS.