[Jetpack] Use the Room framework to access the SQLite database on the Android platform (import dependencies | define the Entity entity class | define the Dao database access object interface | define the database instance class)





1. The core points of using the Room framework




1. build.gradle build script configuration instructions


For the Room framework , different configurations need to be made in the build.gradle build script for development using the Java language and Kotlin language , mainly in the following two configurations:

  • Different plugins are applied;
  • Different ways to import dependent libraries;

application plug-in

Applied plugin differences:

  • If you use the Java language to develop, you only need to import the android plug-in;
plugins {
    
    
    id 'com.android.application'
}
  • If you use Kotlin language development, you need to additionally import kotlin and kotlin-kapt plug-ins on the basis of android plug-ins ;
plugins {
    
    
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}

import dependencies

The difference between importing dependent libraries: if the import is wrong, it will appear

  • If you use Java language development, you need to use annotationProcessor to import annotation processors to generate code during compilation;
    // 导入 Room 依赖库
    implementation 'androidx.room:room-runtime:2.2.5'
    // 导入注解处理器 ( Java )
    annotationProcessor 'androidx.room:room-compiler:2.2.5'
  • If you use Kotlin language development, you need to use kapt to import annotation processors to generate code during compilation;
    // 导入 Room 依赖库
    implementation 'androidx.room:room-runtime:2.2.5'
    // 导入注解处理器 ( Kotlin )
    kapt 'androidx.room:room-compiler:2.2.5'

2. Define the Entity entity class


In the application using the Room framework , the Entity entity class corresponds to the database table . After the Entity entity class is defined, it means that the structure of the database table has been defined;


@Entity annotation

The Entity entity class needs be modified with the @Entity annotation , which can be passed in the tableName parameter, which is used to define the name of the database table;

@Entity(tableName = "student")
class Student {
    
    
}

@PrimaryKey annotation

Define the primary key, use the @PrimaryKey annotation to modify the primary key, and set the autoGenerate = true parameter to make the primary key auto-increment;

The database table column information is defined using the @ColumnInfo annotation , and the parameters in this annotation are:

  • name = "id" defines the column name of the data table;
  • typeAffinity = ColumnInfo.INTEGER defines that the column field type is int integer;
    /**
     * @PrimaryKey 设置主键 autoGenerate 为自增
     * @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
     */
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    var id: Int = 0

@ColumnInfo annotation

To define ordinary fields, you only need to @ColumnInfouse annotations to modify the fields. name = "name"Set the database table name and typeAffinity = ColumnInfo.TEXTset the type of the column to String type;

    /**
     * 姓名字段
     * 数据库表中的列名为 name
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
    lateinit var name: String

@Ignore annotation

modified field

If some fields do not need to be set as database table columns, they are only used in business logic and do not need to be inserted into the database, just use @Ignoreto modify the field;

    /**
     * 有些属性用于做业务逻辑
     * 不需要插入到数据库中
     * 使用 @Ignore 注解修饰该属性字段
     */
    @Ignore
    lateinit var studentInfo: String

modifier function

After using the @Ignore annotation to mark the constructor, the Room framework will not use the constructor;

Among the following three constructors,

  • The Room framework uses the constructor(id: Int, name: String, age: Int)constructor ;
  • Developers use the constructor(name: String, age: Int)and constructor(id: Int)constructors ;
    /**
     * 默认的构造方法给 Room 框架使用
     */
    constructor(id: Int, name: String, age: Int) {
    
    
        this.id = id
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 注解标注构造函数后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(name: String, age: Int) {
    
    
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(id: Int) {
    
    
        this.id = id
    }

3. Define Dao database access object interface


@Dao annotation

The defined Dao database access object interface is an interface interface, which is modified with the @Dao annotation;

/**
 * 数据库访问对象接口 / 使用 @Dao 注解修饰
 * 提供数据库的增删改查方法
 */
@Dao
interface StudentDao {
    
    

@Insert annotation

To insert data into the database, use the @Insert annotation to modify the corresponding abstract method;

    /**
     * 向数据库表中插入元素
     */
    @Insert
    fun insert(student: Student)

@Delete annotation

To delete data from the database, use the @Delete annotation to modify the corresponding abstract method;

    /**
     * 从数据库表中删除元素
     */
    @Delete
    fun delete(student: Student)

@Update annotation

To update the data in the database, use the @Update annotation to modify the corresponding abstract method;

    /**
     * 修改数据库表元素
     */
    @Update
    fun update(student: Student)

@Query annotation

To query the data in the database, use the @Query annotation to modify the corresponding abstract method;

A string parameter can be set in the annotation, which is the SQL statement of the query, and the incoming parameter can be accessed by using a colon ;:

    /**
     * 查询数据库表
     */
    @Query("select * from student")
    fun query(): List<Student>

    /**
     * 根据传入的 id 查询数据库表
     * 在注解中使用 :id 调用参数中的 id: Int
     */
    @Query("select * from student where id = :id")
    fun query(id: Int): List<Student>

4. Define the RoomDatabase database instance class


The defined RoomDatabase database instance class is an abstract class, which needs to inherit the RoomDatabase abstract class, and at the same time use @Databaseannotation decoration,

@Database(entities = [Student::class], version = 1, exportSchema = false)
abstract class StudentDatabase: RoomDatabase() {
    
    

Define abstract methods in this abstract class to obtain database access objects,

    /**
     * 获取 数据库访问 对象
     * 这是必须要实现的函数
     */
    abstract fun studentDao(): StudentDao

Set this class as a singleton class, and create a database when the singleton class object is initialized ;

    companion object {
    
    
        lateinit var instance: StudentDatabase

        fun inst(context: Context): StudentDatabase {
    
    
            if (!::instance.isInitialized) {
    
    
                synchronized(StudentDatabase::class) {
    
    
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }
    }

Initialize the database code:

  • First, call the Room.databaseBuilder function, create a RoomDatabase.Builder object, and pass in parameters such as the Context context, the StudentDatabase class object, and the database name;
  • Then, call the build function of the RoomDatabase.Builder object to create the database;
  • Note: In principle, Room does not allow database operations on the main thread. If you want to operate the database on the main thread, you need call the RoomDatabase.Builder # allowMainThreadQueries function to allow main thread operations;
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()

5. Call the Room framework to access the database


First, obtain the RoomDatabase database instance class, just call its singleton acquisition function, and call this function to create the corresponding database;

        // 获取 StudentDatabase
        var studentDatabase: StudentDatabase = StudentDatabase.inst(this)

Then, obtain the database access object Dao, and obtain it through the abstract method of the RoomDatabase database instance class;

        // 获取数据库访问对象
        var studentDao: StudentDao = studentDatabase.studentDao()

Finally, use the Dao database access object to perform database access operations, and it is recommended to access the database in threads;

        thread(start = true) {
    
    
            // 插入数据
            var s1 = Student("Tom", 18)
            var s2 = Student("Jerry", 16)
            studentDao.insert(s1)
            studentDao.insert(s2)

            // 查询数据
            var students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 插入后首次查询 ) : " + students)

            // 更新数据 , 将学生年龄都设置为 20
            for (i in 0.. students.size - 1) {
    
    
                students[i].age = 20
                studentDao.update(students[i])
            }
            students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 修改后查询结果 ) : " + students)

            // 删除数据
            var s_delete = Student(1)   // 删除的元素只需要传入 id 即可
            studentDao.delete(s_delete)
            students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 删除后查询结果 ) : " + students)
        }




2. Complete code example




1. build.gradle build script


In the build.gradle build script, it mainly imports Kotlin plug-ins and Kotlin annotation plug-ins;

If you use the Java language to develop, you don't need to import these two plug-ins;

    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'

Import Room dependency libraries and annotation processors that generate code at compile time;

    // 导入 Room 依赖库
    implementation 'androidx.room:room-runtime:2.2.5'
    // 导入注解处理器 ( Kotlin )
    kapt 'androidx.room:room-compiler:2.2.5'
    // 导入注解处理器 ( Java )
    //annotationProcessor 'androidx.room:room-compiler:2.2.5'

The complete code is as follows:

plugins {
    
    
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}

android {
    
    
    namespace 'kim.hsl.roomdemo'
    compileSdk 32

    defaultConfig {
    
    
        applicationId "kim.hsl.roomdemo"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
    
    
        release {
    
    
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
    
    
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    
    
        jvmTarget = '1.8'
    }

    viewBinding {
    
    
        // 启用 ViewBinding
        enabled = true
    }
}

dependencies {
    
    

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    // 导入 Room 依赖库
    implementation 'androidx.room:room-runtime:2.2.5'
    // 导入注解处理器 ( Kotlin )
    kapt 'androidx.room:room-compiler:2.2.5'
    // 导入注解处理器 ( Java )
    //annotationProcessor 'androidx.room:room-compiler:2.2.5'
}

2. Entity entity class code


package kim.hsl.roomdemo

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

/**
 * 定义数据库表 Entity 实体 / 同时定义数据库表 和 对鹰的实体类
 * 设置该数据类对应数据库中的一张数据表, 表名为 student
 * 该数据库表中的数据对应一个 Student 类实例对象
 */
@Entity(tableName = "student")
class Student {
    
    
    /**
     * @PrimaryKey 设置主键 autoGenerate 为自增
     * @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
     */
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    var id: Int = 0

    /**
     * 姓名字段
     * 数据库表中的列名为 name
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
    lateinit var name: String

    /**
     * 年龄字段
     * 数据库表中的列名为 age
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)
    var age: Int = 0

    /**
     * 有些属性用于做业务逻辑
     * 不需要插入到数据库中
     * 使用 @Ignore 注解修饰该属性字段
     */
    @Ignore
    lateinit var studentInfo: String

    /**
     * 默认的构造方法给 Room 框架使用
     */
    constructor(id: Int, name: String, age: Int) {
    
    
        this.id = id
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 注解标注构造函数后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(name: String, age: Int) {
    
    
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(id: Int) {
    
    
        this.id = id
    }

    override fun toString(): String {
    
    
        return "Student(id=$id, name='$name', age=$age)"
    }
}

3. Dao database access object interface code


Use the @Dao annotation to modify the interface class;

Use @Insert , @Delete , @Update , @Query annotations to modify the corresponding add, delete, modify, query and other functions;


Complete code :

package kim.hsl.roomdemo

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update

/**
 * 数据库访问对象接口 / 使用 @Dao 注解修饰
 * 提供数据库的增删改查方法
 */
@Dao
interface StudentDao {
    
    
    /**
     * 向数据库表中插入元素
     */
    @Insert
    fun insert(student: Student)

    /**
     * 从数据库表中删除元素
     */
    @Delete
    fun delete(student: Student)

    /**
     * 修改数据库表元素
     */
    @Update
    fun update(student: Student)

    /**
     * 查询数据库表
     */
    @Query("select * from student")
    fun query(): List<Student>

    /**
     * 根据传入的 id 查询数据库表
     * 在注解中使用 :id 调用参数中的 id: Int
     */
    @Query("select * from student where id = :id")
    fun query(id: Int): List<Student>
}

4. RoomDatabase database instance class code


The RoomDatabase database instance class needs to inherit the RoomDatabase abstract class, and use the @Database annotation to modify the abstract class;

Among them, it is necessary to define an abstract function for obtaining database access objects;

Define this class as a singleton class, and create a database when the singleton object is initialized;


Complete code :

package kim.hsl.roomdemo

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [Student::class], version = 1, exportSchema = false)
abstract class StudentDatabase: RoomDatabase() {
    
    
    /**
     * 获取 数据库访问 对象
     * 这是必须要实现的函数
     */
    abstract fun studentDao(): StudentDao

    companion object {
    
    
        lateinit var instance: StudentDatabase

        fun inst(context: Context): StudentDatabase {
    
    
            if (!::instance.isInitialized) {
    
    
                synchronized(StudentDatabase::class) {
    
    
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }
    }
}

5. Access the database by calling the Room framework in the Activity component


First, get the database instance class StudentDatabase;

Then, get the database access object interface StudentDao;

Finally, call a series of methods of the database access object interface StudentDao to access the database;


Complete code :

package kim.hsl.roomdemo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kim.hsl.roomdemo.databinding.ActivityMainBinding
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity() {
    
    
    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(getLayoutInflater())
        setContentView(binding.root)

        // 获取 StudentDatabase
        var studentDatabase: StudentDatabase = StudentDatabase.inst(this)

        // 获取数据库访问对象
        var studentDao: StudentDao = studentDatabase.studentDao()

        thread(start = true) {
    
    
            // 插入数据
            var s1 = Student("Tom", 18)
            var s2 = Student("Jerry", 16)
            studentDao.insert(s1)
            studentDao.insert(s2)

            // 查询数据
            var students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 插入后首次查询 ) : " + students)

            // 更新数据 , 将学生年龄都设置为 20
            for (i in 0.. students.size - 1) {
    
    
                students[i].age = 20
                studentDao.update(students[i])
            }
            students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 修改后查询结果 ) : " + students)

            // 删除数据
            var s_delete = Student(1)   // 删除的元素只需要传入 id 即可
            studentDao.delete(s_delete)
            students = studentDao.query()
            Log.i("MainActivity", "数据库查询结果 ( 删除后查询结果 ) : " + students)
        }


    }
}

Guess you like

Origin blog.csdn.net/han1202012/article/details/130568567