marzo 29, 2024

BitCuco

¡Hola Mundo!

Dao Kotlin – Tutorial de Dao y Room para Android

dao kotlin

Los objetos de acceso a datos (o Dao) proporcionan un componente de acceso abstracto a la base de datos. Aquí te daremos una introducción para realizar operaciones con bases de datos utilizando Dao y Room en Kotlin.

Tanto DAO y Room permiten la realización de operaciones con la base de datos local de la aplicación usando una sintaxis sencilla y de bajo consumo de recursos.

Para crear un Dao, podemos hacer uso de la biblioteca Room para observar los valores obtenidos de la base de datos. Además se recomienda incorporar Retrofit en nuestro proyecto para adquirir los datos remotos, en un tutorial anterior se muestra como configurar Retrofit dentro de tu proyecto.

Creación del modelo para DAO en Kotlin

Una vez configurado Retrofit, procedemos a crear el modelo. Podemos asignar valores por defecto en el constructor, de acuerdo a nuestras necesidades.
Definiremos el siguiente modelo como ejemplo:

@Entity(tableName = "UserInfo")
data class userInfo constructor(
        @NonNull
        @PrimaryKey(autoGenerate = true)
        @SerializedName("userId") var userId: Int,
    @SerializedName("userName") val userName: String,
    @SerializedName("userAddress") val userAddress: String,
    @SerializedName("userPhoneNumber") val userPhoneNumber: String
) : Serializable

Creación de la Database

Para almacenar en Room requerimos crear bases de datos de la cuál tenga acceso el Dao de Kotlin y pueda realizar operaciones, es decir que contenga las tablas en donde contenga las entidades que queremos almacenar. Se recomienda que sea un archivo CoreDatabase.kt, que en el caso de la entidad el párrafo anterior, deberá contener una tabla userInfo, como se muestra en el ejemplo siguiente:

import android.arch.persistence.db.SupportSQLiteDatabase
import android.arch.persistence.room.*
@Database(
        version = 1,
        entities = [
            userInfo::class
        ],
        exportSchema = false
)
@TypeConverters(Converters::class)
abstract class CoreDatabase : RoomDatabase() {
    companion object {
        private const val DATABASE_NAME = "Core.db"
        @Volatile
        private var INSTANCE: CoreDatabase? = null
        /**
         * Singleton que devuelve un objeto CoreDatabase
         */
        fun getInstance(context: Context): CoreDatabase =
            INSTANCE ?: synchronized(this) {
                INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
            }
        /**
         * Crea una instancia a CoreDatabase
         */
        private fun buildDatabase(context: Context) =
            Room.databaseBuilder(context.applicationContext,
                    CoreDatabase::class.java, DATABASE_NAME)
            .addMigrations(version_0_1)
            .build()
         /**
          * Creamos la base de datos UserInfo
          */
         private val version_0_1 = object : Migration(0, 1) {
         override fun migrate(database: SupportSQLiteDatabase) {
            val sqlStatement = "CREATE TABLE IF NOT EXISTS `UserInfo` (`userId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userName` TEXT NOT NULL, `userAddress` TEXT NOT NULL, `userPhoneNumber` TEXT)"
            database.execSQL(sqlStatement)
         }
     }
     abstract fun userInfoDao(): UserInfoDao
}

Creación del Dao en Kotlin

Después de construir nuestra base de datos y la tabla userInfo, procedemos a crear un archivo para los queries, al cual llamaremos UserInfoDao.kt, el cual consiste de una interfaz que implementa las consultas de nuestro Dao.

import android.arch.persistence.room.*
@Dao
 interface UserInfoDao : CoreDao {
 /**
  * Ejemplo de consultas
  */ 
 /**
  * Insertar una lista de usuarios
  */
 @Insert(onConflict = OnConflictStrategy.REPLACE)
 fun saveUsers(data: List<UserInfo>)
 /**
  * Obtener una lista de todos los usuarios
  * Flowable es parte de Retrofit y es usado para un listado
  */
 @Query("SELECT * FROM UserInfo")
 fun getAllUsers(): Flowable<List<UserInfo>>
 /**
  * Obtener la información de un usuario en particular
  * El contenido de una variable es antecedida con dos puntos
  */
 @Query("SELECT * FROM UserInfo WHERE userId = :userId LIMIT 1")
fun getUserById(userId: Int): Single<UserInfo?>
 /**
  * Actualizar nombre de un usuario
  */
@Query("UPDATE UserInfo SET userName = :userNam WHERE userId = :userId")
fun updateActivePromotion(userId: Int, userNam: String)
 /**
  * Eliminar todos los usuarios
  */
 @Query("DELETE FROM UserInfo")
 fun dropTableUserInfo()
}

Todas éstas operaciones se realizan dentro de la Base de Datos local, la cual se debe definir con anterioridad. RxJava nos da la opción para regresar diferentes tipos de Observable asíncronos, por ejemplo Single, Maybe, Flowable y Completable, los cuáles vale la pena repasar más adelante. Así mismo podemos utilizar algunas herramientas como DB Browser para depurar nuestro código.

Invocación del Dao desde el Repository de Kotlin

A nivel de Repository, la invocación de los métodos de Dao se manejan de la misma que el llamado a los métodos de ApiService. Para llamar a un método de Dao desde el Repository, por ejemplo teniendo UserInfoRepository.kt como nuestro repository, la invocación de un método se verá así:

class UserInfoRepository
 @Inject constructor(
     //Desde Dao
         private val userInfoDao: UserInfoDao,
     //Desde Endpoints
         private val userInfoApiService: UserInfoApiService
 ) {
/**
 * Obtener lista de usuarios
 */
fun getAllUsers() : Observable<List<UserInfo>>{
    return userInfoDao.getAllUsers()
}
/**
 * Obtener información de un usuario
 */
fun getUserId(userId: Int) : Observable<UserInfo?>{
    return userInfoDao.getUserById(userId)
}
/**
 * ... Todas los demás métodos ...
 */
}

Implementación del ViewModel

Se retornan los Observer al recibir respuesta desde el Repository, y por lo tanto se deben implementar objetos del tipo MutableLiveData para definir una rutina una vez que se obtienen los valores. Es aquí donde radica la importancia del modelo MVVM.

Por medio de de inyección de dependencias, es transparente el manejo del resultado arrojado y proceda a realizar las operaciones de Dao en Room en forma transparente. Así mismo se toman los valores, sin hacer dinstinción al final si éstos provinieron de Dao o de respuesta de un Endpoint.

La implementación en el ViewModel es por lo tanto similar a la mostrada en este tutorial de implementación de solicitudes remotas en Kotlin.