Kotlin — Anko & the SQLite

Alejandro Moya
Codelitt
Published in
3 min readMay 22, 2019

--

In the previous post we went through a layout DSL from Anko that allows dynamic UI building entirely from code. Today we are going to check some great SQLite extensions that will make accessing a SQLite database look like one of the simplest things in our daily work.
I personally prefer Realm over SQLite for speed, API and it’s core written in C++, but i know many projects rely on SQLite, and we are covering all the good things in Anko, so let’s be good with it.

In the regular way, to open a SQLite database we need to subclass SQLiteOpenHelper, in Anko we need to subclass ManagedSQLiteOpenHelper and override some methods:

class MyDatabaseOpenHelper(ctx: Context) : ManagedSQLiteOpenHelper(ctx, “MyDatabase”, null, 1) {
companion object {
private var instance: MyDatabaseOpenHelper? = null
@Synchronized
fun getInstance(ctx: Context): MyDatabaseOpenHelper {
if (instance == null) {
instance =
MyDatabaseOpenHelper(ctx.getApplicationContext())
}
return instance!!
}
}
override fun onCreate(db: SQLiteDatabase) {
// Here you create tables
db.createTable(“User”, true,
“id” to INTEGER + PRIMARY_KEY + UNIQUE,
“name” to TEXT,
“email” to BLOB)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int,
newVersion: Int) {
// Here you can upgrade tables, as usual
db.dropTable(“User”, true)
}
}
// Access property for Context
val Context.database: MyDatabaseOpenHelper
get() = MyDatabaseOpenHelper.getInstance(getApplicationContext())

The access property created makes it easy to use the database:

database.use {
//’this’ refers to the SQLiteDatabase instance
}

This is similar to:

val db = database.writableDatabase

But this last example requires running the commands and calling close() when finished.

In the previous snippet you see some details about how to create and drop tables:

db.createTable(“User”, true, 
“id” to INTEGER + PRIMARY_KEY + UNIQUE,
“name” to TEXT,
“email” to BLOB)
///db.dropTable(“User”, true)

Following we should see how to insert, update and delete:

database.use {
insert(“User”,
“id” to 42,
“name” to “John”,
“email” to “user@domain.org”)

update(“User”, “name” to “Alice”)
.where(“id = {userId}”, “userId” to 42)
.exec()
//or
update(“User”, “name” to “Alice”)
.`whereSimple`(“id = ?”, 42)
.exec()
val numRowsDeleted = delete(“User”,
“id = {userID}”,
“userID” to 42)
}

We could use a transaction for all these operations:

database.use {
transaction {
insert(“User”,
“id” to 42,
“name” to “John”,
“email” to “user@domain.org”)

update(“User”, “name” to “Alice”)
.where(“id = {userId}”, “userId” to 42)
.exec()
//or
update(“User”, “name” to “Alice”)
.`whereSimple`(“id = ?”, 42)
.exec()
val numRowsDeleted = delete(“User”,
“id = {userID}”,
“userID” to 42)
}
}

There are also replace() insertOrThrow() replaceOrThrow() methods that can be used accordingly.

Now we should know how to query data right?:

val db = database.readableDatabasedb.select(“User”, “email”).exec {
//you receive a Cursor with the email column in the block
}
db.select(“User”).`whereSimple`(“id = ?”, 42).exec {
//you receive a Cursor with the User columns in the block
}

There are more options for the query builder, also there’s a parsing helper that maps the cursor to an array or map.

This was the last post about Anko, i hope you found this helpful and encouraging to use these libraries.

--

--

Alejandro Moya
Codelitt

Mobile developer, Father, geek, this is my first attempt at having a blog, be kind 😄