Bases de datos en Android con Anko y Kotlin: SQLite nunca fue tan sencillo (KDA 25)
Antonio Leiva

Hay que reconocer que escribir bases de datos en Android es bastante aburrido.

Todo el código necesario para trabajar con SQLite es horrible.

Por suerte, ya hay bastantes librerías que nos simplifican un poco la tarea.

Con Anko, sin embargo, podemos seguir trabajando tan a bajo nivel como cuando usamos el framework, pero librarnos de algunas de las partes más tediosas de su implementación. Hoy vamos a ver cómo.

¿Te gustaría comenzar hoy a dar el siguiente paso? Te recomiendo que entres en mi training gratuito aquí

Crea tu base de datos con Anko

Vas a ver aquí cómo crear tu base de datos desde cero. En Android, necesitarás un SQLiteOpenHelper, del que recuperas la base de datos, que luego necesitas recordar cerrar tras las peticiones. Anko hace esto por ti.

Para ello necesitas incluir la dependencia de SQLite para Anko:

compile 'org.jetbrains.anko:anko-sqlite:0.9'

Implementa ManagedSQLiteOpenHelper

Si utilizas esta clase, que extiende SQLiteOpenHelper, podrás crear bloques de código en los que ejecutar las operaciones de base de datos, de la siguiente forma:

database.use { 
    ...
}

El contenido de los corchetes es una función de extensión sobre la clase SQLiteDatabase, así que puedes llamar a los métodos de la misma directamente.

¿Cómo implementamos esta clase? Basándonos en la documentación de Anko, la forma recomendad es la siguiente:

class MySqlHelper(ctx: Context) : ManagedSQLiteOpenHelper(ctx, "mydb") {

    companion object {
        private var instance: MySqlHelper? = null

        @Synchronized
        fun getInstance(ctx: Context): MySqlHelper {
            if (instance == null) {
                instance = MySqlHelper(ctx.applicationContext)
            }
            return instance!!
        }
    }

    override fun onCreate(db: SQLiteDatabase) {
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    }

}

// Access property for Context
val Context.database: MySqlHelper
    get() = MySqlHelper.getInstance(applicationContext)

Nos creamos un pequeño singleton que guardará la instancia del helper, de forma sincronizada para que diferentes hilos no puedan generar más de una instancia.

Además, creamos una propiedad de extensión para el contexto, de tal forma que cualquier clase que exienda de Context pueda acceder a la base de datos directamente.

Esto nos permite ya utilizar el código inicial.

Define la estructura de la tabla

Para crear nuestra base de datos, lo único que tenemos que hacer es implementar el método onCreate del helper, y utilizar la función de extensión createTable que nos provee Anko:

override fun onCreate(db: SQLiteDatabase) {
    db.createTable("Person", true,
            "_id" to INTEGER + PRIMARY_KEY,
            "name" to TEXT,
            "surname" to TEXT,
            "age" to INTEGER)
}

El primer parámetro es el nombre de la base de datos, y el segundo comprueba que no exista la tabla antes de hacer el create .

El tercero es un vararg de pares. Es decir, que se pueden añadir tantos como se quiera. Como ves, los pares se crean con la forma A to B. Esto es lo que se llama función infija, y se especifica con la palabra reservada infix.

La segunda parte de los pares son constantes de la clase SqlType. Te recomiendo que le eches un vistazo a la implementación, porque es muy interesante. Aquí se hace uso de la sobrecarga de operadores, de la que ya hablamos en su momento.

Inserta y consulta datos

Todo se vuelve mucho más sencillo con Anko. En vez de tener que crearte tu propio ContentValue al que añadir todos los datos durante la inserción, puedes usar una función de extensión sobre el objeto de base de datos, que queda tal que así:

database.use {
    insert("Person",
            "_id" to 1,
            "name" to "John",
            "surname" to "Smith",
            "age" to 20)
}

Para las consultas, hay varias formas de realizarlas. En una de ellas se pueden añadir nombres a las variables de la query e incluir los valores como pares:

select("Person")
        .where("(_id = {id}) and (name = {name})",
                "id" to 1,
                "name" to "John")

Y hay otra, más parecida a la que se utiliza en el framework de Android, que permite incluir interrogación y posteriormente los valores. Todos ellos deben ser String en este caso:

select("Person")
        .whereSimple("(_id = ?) and (name = ?)",
                1.toString(), "John")

A mí personalmente en este caso me parece más sencilla la segunda opción.

También se puede aplicar todas las operaciones típicas de base de datos como limit, orderBy, having o groupBy. Puedes ver todas las operaciones en la documentación de Anko.

Para tratar el resultado a partir del cursor, Anko también nos provee de distintas funciones, como parseSingle (para un resultado) o parseList (para varios). Estas funciones reciben un rowParser.

Hay un montón de parseadores distintos. Uno interesante es el MapRowParser, que mapea las columnas a un mapa.

Con este parser y delegado map, puedes parsear directamente los valores desde un mapa a una clase. Esto lo puedes ver explicado en mi libro sobre Kotlin.

Conclusión

Si bien es verdad que hay librerías que simplifican mucho más el trabajo con bases de datos, y sobre todo la hacen más segura con comprobaciones de tipos, para cosas sencillas nos puede ser más que suficiente Anko.

Nos ahorra muchas de las cosas que hacen que trabajar con bases de datos sea un suplicio, así que es una buena alternativa para bases de datos simples.

Además, nos demuestra otras formas de utilizar el lenguaje que te pueden ser muy útiles cuando te estés enfrentando a otros problemas.

Si todo esto te apasiona tanto como a mí, te animo a que te apuntes a mi training gratuito donde te contaré todo lo que necesitas para aprender a crear tus Apps Android en Kotlin desde cero

Quizá también te interese…

¿Qué es Kotlin Multiplataforma?

¿Qué es Kotlin Multiplataforma?

En el mundo actual, donde los dispositivos móviles están presentes en nuestra vida diaria, es fundamental para los desarrolladores crear aplicaciones que se adapten a diferentes sistemas operativos. Kotlin Multiplataforma es una herramienta que facilita la creación de...

5 trucos de Kotlin para escribir código más eficiente en Android

5 trucos de Kotlin para escribir código más eficiente en Android

El lenguaje de programación Kotlin se ha convertido en el más popular para el desarrollo de aplicaciones de Android en los últimos años. Su sintaxis concisa y moderna, junto con su capacidad para mejorar la eficiencia de código, lo convierten en una opción atractiva...

Cómo crear un backend en Kotlin usando Ktor

Cómo crear un backend en Kotlin usando Ktor

Ktor es un framework de servidor web ligero y rápido para Kotlin, desarrollado por JetBrains. Es ideal para crear aplicaciones web y servicios RESTful, y es muy fácil de usar y configurar. En este artículo, vamos a ver cómo crear un backend para una aplicación de...

2 Comentarios

  1. Vicente

    Muchas gracias por tus cápsulas-post de kotlin 🙂

    Una pregunta, ¿sabes si existe algún tipo de parser que permita hacer un insert usando anko de un objeto directamente?

    Es decir, un parser en el que a partir del objeto a insertar extraiga las Pairs para pasarselas al insert, sin necesidad de ir campo a campo

    Responder
    • Antonio Leiva

      No conozco nada por el estilo, la verdad… Si descubres algo, cuéntame!

      Responder

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de DevExpert, S.L.U., con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *