instructions

As part of the Android Architecture’s ORM, Android Room is very simple to access.

First clear Room can do what, simple summary, can let you turn a line of SQL statement into an object, is now the best USE of ORM framework, of course, this is nonsense, the official can take out, certainly better than the third party. Try it first:

Simply insert data without writing SQL:

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg record: Record)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(record: Record)
Copy the code

Query data, one line of SQL, one function declaration

@Query("SELECT * FROM Record")
fun getAll(a): List<Record>
Copy the code

And SQL has code hints and syntax checks.

Next, we use Room on an existing project, using the new ORM framework without making any changes to the database structure.

Add the Room

def room_version = "1.1.0" // for latest rc, use "1.1.1-rc1"

implementation "android.arch.persistence.room:runtime:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"
Copy the code

Entity

Now the project data volume has a Record table, create SQL statement as

CREATE TABLE Record (
    _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    date INTEGER UNIQUE NOT NULL.records TEXT,
    need_sync INTEGER DEFAULT 0
);
Copy the code

The primary key is _id, data is an integer that stores the time, records is a string that is a JSON object, and need_sync is a Boolean that is stored as an integer in the database.

What I want to do:

  • _idIn the data class, the name isid
  • dateAs the UNIQUE
  • dateRead directly as a LocalDate object
  • recordsRead directly as a Bean object
  • need_syncRead it directly as Boolean, and of course change the name of the data class

The final Entity class declaration is:

@Entity(tableName = "Record", indices = [(Index(value = arrayOf("date"), unique = true)))class Record {
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "_id")
    var id: Long = 0

    var date: LocalDate? = null
    var records: Bean? = null

    @ColumnInfo(name = "need_sync")
    var needSync = false
}
Copy the code

Except for class declarations, we do not need SQL statements to create tables

Dao

RecordDao, used to access data objects:

@Dao
interface RecordDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(vararg record: Record)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(record: Record)

    @Delete
    fun delete(record: Record)

    @Delete
    fun deleteAll(vararg record: Record)

    @Update
    fun update(record: Record)

    @Query("SELECT * FROM Record")
    fun getAll(a): List<Record>

    @Query("SELECT * FROM Record WHERE date = :date")
    fun getByDate(date: LocalDate): List<Record>
}
Copy the code

Directly insert, delete, update, is don’t write SQL, custom queries, or need to write SQL, you can directly binding function parameters in the SQL statement, as long as before the parameter name plus “:” ok, like getByDate: the date is the date parameter identification function is parameter in the SQL:

@Query("SELECT * FROM Record WHERE date = :date")
fun getByDate(date: LocalDate): List<Record>
Copy the code

@query SQL statement not only has code hint, but also has syntax check, write wrong table name and function parameter name will error, good news for the disabled party.

Database

Now that Entity and Dao are declared, we need to create the database. Remember how we did it before:

  • Inheritance SQLiteOpenHelper
  • onCreateExecute SQL statements to create the database
  • onUpgradeFor Migration
  • execSQLTo obtainCursor
  • theCursorConvert to object

What about Room?

No SQLiteOpenHelper, no onCreate:

@Database(entities = [(Record::class)], version = 10)
abstract class AppDataBase : RoomDatabase() {

    abstract fun recordDao(a): RecordDao
}
Copy the code

Now that the database creation declaration is complete and Room is used, accept these points:

  • Don’t needSQLiteOpenHelper
  • Don’t needCursor
  • May evenSQLiteDatabaseDon’t need to,

TypeConverters

Is that all the code to create the database? Of course not, we also need TypeConverters and Migration,

Date is stored in the data in the form of Long, which needs to be converted into a LocalDate object when reading, and to be converted into a LocalDate object when storing. For a conversion relationship, we only need to declare a static function, with any name. Parameters and return values are of type corresponding to conversion relationships.

class DbTypeConverters {
    companion object {

        @TypeConverter
        @JvmStatic
        fun toLocalDate(value: Long): LocalDate =
                LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneId.systemDefault()).toLocalDate()

        @TypeConverter
        @JvmStatic
        fun toLocalDate(value: LocalDate): Long =
                value.atStartOfDay(ZoneId.of("UTC")).toInstant().toEpochMilli()
    }

}
Copy the code

Then add TypeConverters to the Database

@Database(entities = [(Record::class)], version = 10)
@TypeConverters(DbTypeConverters::class)
abstract class AppDataBase : RoomDatabase() {

    abstract fun recordDao(a): RecordDao
}
Copy the code

Migrations

Database upgrade, what we need to declare is a Migration,

object PeriodDbMigration {

    @JvmField
    val MIGRATION_1_2 = object : Migration(1.2) {

        override fun migrate(database: SupportSQLiteDatabase) {
            // update}}@JvmField
    val MIGRATION_3_4 = object : Migration(3.4) {

        override fun migrate(db: SupportSQLiteDatabase) {
            // update}}}Copy the code

Same as onUpgrade for SQLiteOpenHelper, except that each upgrade is split into a Migration operation.

Then create the database:

Add the database upgrade operation with addMigrations,

val database = Room.databaseBuilder(application, PeriodDataBase.class."database.db")
                .addMigrations(PeriodDbMigration.MIGRATION_1_2, PeriodDbMigration.MIGRATION_3_4)
                .allowMainThreadQueries()
                .build();
Copy the code

AllowMainThreadQueries () allows queries to be performed on the main thread.

use

The data is typically used as a singleton and then the Dao function is called:

val all = database.recordDao().getAll()
Copy the code