【Android】Room - a replacement for SQLite

Why was SQLite replaced by Room?

Why will SQLite be replaced?

SqliteIt has a history of more than 20 years since its inception in 2000. In these more than 20 years, the Sqliteoriginal 1.0 version has been upgraded to the current 3.0 version. However, even with the latest 2.3.0 version supported by Android, it is still available on Android. There are still a series of shortcomings, as follows:

  • There is no compile-time validation of raw SQL queries.
  • A lot of boilerplate code is required to convert between SQL queries and data objects.
  • While these APIs are powerful, they are quite low-level and require a lot of time and effort to use.

In response to Sqlitea series of problems, the goals of realm(applicable to ios, Android), ObjectBox(cross-end, claiming to be the fastest), greenDaoand other local databases are to replace SQLite, and even later, even the official released a new database - — Room, is this to be completely eliminated Sqlite?

The answer is no. The above databases greenDAO are beingRoom modified and optimized. It is a product developed by the development team of. They recommend the database to everyone on the Github homepage, but has not been updated for more than a year. Perhaps, the peak of Yes has passed, and it is difficult to stand on the top again, so they are slowly starting to use it. Losing hope for the future (personal guess).SqliteObjectBoxgreenDAO greenDAOObjectBoxgreenDAOgreenDao

So why SQLiteis it replaced Roominstead of greenDao? Personally, I think this is entirely due to the official "official announcement". On the introduction page and usage guide found on the Android Developers official website SQLite, you will find words like this:

we highly recommend using the Room Persistence Library as an abstraction layer for accessing information in your app's SQLite databases
.

Insert image description here
The reasons for giving up SQLiteand persuading us to use Roomare SQLitethe disadvantages and Roomadvantages.

Roomadvantage:

  • Simplified database migration path.
  • Compile-time validation of SQL queries.
  • Convenient comments minimize duplication and error-prone boilerplate code.

Integrated Room

Room contains three main components, namely:

  • Database: A database class that holds a database and serves as the primary access point for the underlying connection to an application's persistent data.
  • Entity: represents the data entity of the table in the application database.
  • Dao: Data access object that provides methods that your application can use to query, update, insert, and delete data in the database.

Import dependencies

implementation("androidx.room:room-runtime:2.4.2")
annotationProcessor("androidx.room:room-compiler:2.4.2")

// 使用 Kotlin 注释处理工具 (kapt)
kapt("androidx.room:room-compiler:2.4.2")

Note: Kotlin plugin supports annotation processors such as Dagger or DBFlow. In order for them to work with Kotlin classes, plugins kaptneed to be applied kotlin-kapt.

apply plugin: 'kotlin-kapt'

Click to view the latest version dependencies

There are three steps to use Room, namely Database, Entity, and Dao. Data can only be written, modified, and other operations after each creation is completed.

Entity (data entity)

In Room, you can define entities to represent the objects you want to store. Each entity corresponds to a table in the associated Room database, and each instance of an entity represents a row of data in the corresponding table.

The Kotlin version of Entity is written differently from the Java version of Entity. The normal way of writing the Java version of Entity is to create a new entity class and implement the get and set methods of the variables. The Kotlin version of Entity uses keywords. In Kotlin, the marked class is data classused data class. is a data class, which will automatically override the , , methods Anyof Kotlin's super class . For more detailed information, please go to → Kotlin Data Class (Data)equals(other: Any?)hashCode()toString()

The data class declared data classas Room needs to be declared using @Entityannotations. By default, Room will use the class name as the database table name. If you do not want the class name to be the same as the database table name, you can @Entityset tableNameparameters in the annotation, such as: @Entity(tableName = "自定义的数据库表名"), add parameters After that, the database table name generated by this class will no longer be the class name.

@Entity
data class Classes(
    @PrimaryKey val classesId: String,
    @ColumnInfo val classesName: String
)

Other notes

Annotation Describe
@PrimaryKey Used to uniquely identify each row in the corresponding database table
@ColumnInfo Define the column names of the data table
@Ignore Do not add fields to the data table
@NonNull The return value of a field or method cannot be null

@EntityFor detailed usage, see: Using Room entities to define data

Dao (data access object)

Dao: Provides methods used by the rest of the application to interact with the data in the data table.

Dao is an interface class. There is no need to write a method body. Annotations can be used directly instead. Addition, deletion, modification and query correspond to the following four annotations:

Annotation Describe
@Insert increase
@Delete delete
@Update change
@Query check

Annotations are used as follows:

@Dao
interface ClassesDao {
    
    
    /**
     * 增加多个班级
     */
    @Insert
    fun addMultipleClasses(vararg classes: Classes)
	/**
     * 删除某条数据
     */
    @Delete
    fun deleteClasses(classes: Classes)
    /**
     * 修改某条数据
     */
    @Update
    fun updateClasses(classes: Classes)
    /**
     * 查询classes表的数据
     */
    @Query("select * from classes")
    fun getAllClasses() : List<Classes>
}

In Room, the query with value is represented by colon. The following code indicates that the className to be searched is equal to the value passed when calling the interface.

@Query("select * from classes where className = :classesName")
fun getAllClasses(classesName: String) : List<Classes>

For detailed usage of Dao, see: Using Room DAO to access data

Database

Entity and Dao have been defined. The last step is to create a database class to save the data. The created class must meet the three conditions of the database:

  • The class must be RoomDatabasean abstract class that extends the class.
  • For each Dao class associated with a database, the database class must define an abstract method that takes zero parameters and returns an instance of the Dao class.
  • The class must be annotated with an annotation @Databasecontaining entitiesan array listing all data entities associated with the database (including the database version).
@Database(entities = [Classes::class/*数据库包含的实体*/], version = 1, exportSchema = false)
abstract class SchoolDatabase : RoomDatabase() {
    
    
    /**
     * 调用该方法获取Dao,来调用Classes表的接口方法
     */
    abstract fun classDao(): ClassesDao
}

use

Room.databaseBuilder(applicationContext, SchoolDatabase::class.java, "数据库名称")
     .build()
     .classDao()
     .addClasses(classes)

Effect

Insert image description here

data migration

Why does the database need to be migrated?

You may encounter such a problem during the development of a local database. After modifying the fields of the database, a crash will occur upon restarting.

Some students who encounter this problem may use keywords like this to search: solutions to database field modification crashes. The search results will tell you to uninstall the app and reinstall it, and the problem will be solved. However, this seemingly correct method is actually fatal.

The local database is modified once, packaged and released. If the user uses the local database after updating the app, an Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.exception error will be reported.

Insert image description here
If the interface of an app is not loaded within 8 seconds, 70% of users will be lost. This is the 8-second rule. So how many users will be lost if it crashes once? To solve the above problems, only the database can be migrated, and data migration is divided into automatic migration and manual migration.

Automatic migration

Automatic migration provides four annotations for automatic migration, which are:

How to use it:

// 版本更新前的数据库类.
@Database(
  version = 1,
  entities = [User::class]
)
abstract class AppDatabase : RoomDatabase() {
    
    
  ...
}

// 版本更新后的数据库类.
@Database(
  version = 2,
  entities = [User::class],
  exportSchema = true,
  autoMigrations = [
    AutoMigration (from = 1, to = 2)
  ]
)
abstract class AppDatabase : RoomDatabase() {
    
    
  ...
}

Since the official currently only provides the above four annotations for automatic migration, how to add fields has become a mystery. If you learned about the new data table fields for automatic migration while watching this article, I hope you can join us in the comment area. share.

Note:
1. Automatic migration exportSchemamust be set trueto avoid migration failure.
2. Automatic migration is only applicable to 2.4.0-alpha01 and higher versions. For lower versions and situations involving complex architecture changes, manual migration must be used.

Reference article: Room database migration

Manual migration

The first step in manual database migration is to modify the data table structure.

@Entity
data class Classes(
    @PrimaryKey(autoGenerate = true) val classesId: Int = 0,
    @ColumnInfo(name = "className") var classesName: String,
    // 新增的列
    @ColumnInfo(name = "classesNum") var classesNum: String
)

The method used for manual migration RoomDatabase.Builderis addMigrations(@NonNull Migration... migrations)to put the new Migrationclass in to complete the migration.

The bottom layer of Room uses SQLite. Data migration uses the SQLite execSQL(String sql)method to execute SQL statements to modify the database to complete the migration. The code is as follows:

var db: SchoolDatabase ?= null
// 单例模式的双重检查锁
fun getDataBase(context: Context) : SchoolDatabase{
    
    
    if (db == null){
    
    
        synchronized(SchoolDatabase::class.java){
    
    
            if (db == null){
    
    
                db = Room.databaseBuilder(context.applicationContext, SchoolDatabase::class.java, "school")
                    // .fallbackToDestructiveMigration()
                    // 添加数据迁移
                    .addMigrations(MIGRATION_1_TO_2)
                    .build()
            }
        }
    }
    return db as SchoolDatabase;
}

// Migration实例的两个参数指的是当前版本升级到什么版本
val MIGRATION_1_TO_2 : Migration = object : Migration(1, 2) {
    
    
    override fun migrate(database: SupportSQLiteDatabase) {
    
    
        //  添加新的列使用 底层SQLite + sql 语法,其它增删改查亦是如此
        database.execSQL("alter table classesNum add column 新增的列名 列名的数据类型 default 'null'")
    }
}

Finally, don’t forget to change the @Databaseannotation parameters on the database class name to the latest version, and run again to complete the migration.version

Reference: Android development basic tutorial

Used with RxJava

When Room performs database operations, it uses a sub-thread by default. If it needs to be executed in the main thread, it can be called to Room.databaseBuilderdisable allowMainThreadQueries()Room's main thread query check. However, this operation is not recommended, as it will increase the probability of triggering ANR.

ThreadIf you create a new one and implement the interface every time you perform a Room operation Runnable, wouldn't it be easier to trigger ANR?

To this end, the official has launched a library that is used in conjunction with Rxjava to facilitate switching between threads.

// optional - RxJava3 support for Room
implementation("androidx.room:room-rxjava3:2.4.2")
// RxJava3
implementation ("io.reactivex.rxjava3:rxjava:3.1.3")
implementation ("io.reactivex.rxjava3:rxandroid:3.0.0")

For specific operations combined with RxJava, please refer to the articles:
1. Room database practice: use and encapsulation with RxJava
2. Room with RxJava2, usage methods, experience and precautions


Code for this article: [Android] Room - SQLite replacement Demo

Reference document
1. Android Room code example
2. Android Developers —— Room
3. Android Developers —— Room usage guide
4. Android Developers —— Defining data using Room entities

Guess you like

Origin blog.csdn.net/baidu_41616022/article/details/125424197