Android – Room Persistence Library

by Cao Ngọc Hiệp
261 views

1. Room database là gì?

Room là một Persistence Library được google giới thiệu trong sự kiện google I/O mới đây, nó là một abstract layer cung cấp cách thức truy câp thao tác với dữ liệu trong cơ sở dữ liệu SQLite. Các thành phần: Database, DAO (Data Access Object) và Entity.

Các ứng dụng sử dụng một lượng lớn dữ liệu có cấu trúc có thể hưởng lợi lớn từ việc lưu lại dữ liệu trên local thông qua Room Database. Trường hợp thường gặp nhất là chỉ cache những dữ liệu có liên quan. Nếu làm vậy thì khi thiết bị không có kết nối internet thì user vẫn có thể truy cập data đấy khi đang offline. Mọi dữ liệu được phát sinh hay thay đổi do user sau đó sẽ được đồng bộ với server khi họ online trở lại.

Room Database đơn giản hóa việc mã hóa và giảm thiểu các hoạt động liên quan đến cơ sở dữ liệu. Nếu các bạn đã chán ngán với việc phải khai báo các câu lệnh rất dài mới có thể xây dựng được database thì hãy sử dụng Room ngay nhé!

2. Đặc điểm của Room database

  • Trong trường hợp SQLite, Không có xác minh thời gian biên dịch của các truy vấn SQLite thô. Nhưng trong Room có ​​xác thực SQL tại thời điểm biên dịch.
  • Khi lược đồ của bạn thay đổi, bạn cần cập nhật các truy vấn SQL bị ảnh hưởng theo cách thủ công. Room giải quyết vấn đề này.
  • Bạn cần sử dụng nhiều mã soạn sẵn để chuyển đổi giữa các truy vấn SQL và các Data objects. Tuy nhiên, Room ánh xạ các đối tượng cơ sở dữ liệu của chúng tôi tới Data objects mà không cần mã soạn sẵn.
  • Room được xây dựng để hoạt động với LiveData để quan sát dữ liệu, trong khi SQLite thì không.

3. Cách import Room

Mở build.gradle (app) và thêm dòng lệnh sau:

dependencies {
    def room_version = "2.4.0"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"

    // optional - RxJava2 support for Room
    implementation "androidx.room:room-rxjava2:$room_version"

    // optional - RxJava3 support for Room
    implementation "androidx.room:room-rxjava3:$room_version"

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "androidx.room:room-guava:$room_version"

    // optional - Test helpers
    testImplementation "androidx.room:room-testing:$room_version"

    // optional - Paging 3 Integration
    implementation "androidx.room:room-paging:2.4.0"
}

4. Các thành phần chính trong Room

Có 3 thành phần chính trong Room:

  • Database

Có thể dùng componenet này để tạo database holder. Annotation sẽ cung cấp danh sách các thực thể và nội dung class sẽ định nghĩa danh sách các DAO (đối tượng truy cập CSDL) của CSDL. Nó cũng là điểm truy cập chính cho các kết nối phía dưới.

@Database(
    entities = [
        School::class,
        Student::class
    ],
    version = 2,
    exportSchema = false
)
abstract class SchoolDataBase : RoomDatabase() {

    abstract fun schoolDAO(): ISchoolDAO

    abstract fun studentDAO(): IStudentDAO

    companion object {
        @Volatile
        private var INSTANCE: SchoolDataBase? = null

        fun getInstance(context: Context): SchoolDataBase = INSTANCE ?: synchronized(this) {
            return Room.databaseBuilder(
                context.applicationContext,
                SchoolDataBase::class.java,
                Constant.SCHOOL_DATABASE
            ).build().also {
                INSTANCE = it
            }
        }
    }
}
  • Entity

Component này đại diện cho một class chứa một row của database. Với mỗi một entity thì một database table sẽ được tạo để giữ các items tương ứng. Nên tham chiếu lớp enity thông qua mảng entities trong class Database.

Mỗi Object phải xác định ít nhất 1 trường làm khóa chính. Ngay cả khi chỉ có 1 trường, bạn vẫn cần chú thích trường này bằng anotation @PrimaryKey. Ngoài ra, nếu bạn muốn Room gán ID tự động cho các thực thể, bạn có thể đặt thuộc tính autoGenerate của @PrimaryKey.(Trường hợp thuộc tính là int, long).

@Entity(tableName = SCHOOL_TABLE)
data class School(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = SCHOOL_ID)
    val schoolId: Int = 0,
    @ColumnInfo(name = SCHOOL_NAME)
    val schoolName: String,
    @ColumnInfo(name = SCHOOL_ADDRESS)
    val schoolAddress: String
)

Trường hợp các bạn muốn đánh index cho một số trường trong database để tăng tốc độ truy vấn các bạn có thể sử dụng như sau:

@Entity(indices = {@Index(value = {"first_name", "last_name"}})

Định nghĩa foreignKeys. Ví dụ bạn có đối tượng khác là Student và bạn có thể định nghĩa relationship tới đối tượng School thông qua @ForeignKey annotation như sau:

@Entity(
    tableName = STUDENT_TABLE,
    foreignKeys = [ForeignKey(
        entity = School::class,
        parentColumns = [SCHOOL_ID],
        childColumns = [SCHOOL_ID],
        onDelete = ForeignKey.CASCADE

    )]
)
data class Student(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = STUDENT_ID)
    val studentId: Int = 0,
    @ColumnInfo(name = SCHOOL_ID)
    val schoolId: Int,
    @ColumnInfo(name = STUDENT_NAME)
    val studentName: String,
    @ColumnInfo(name = STUDENT_GRADE)
    val studentGrade: Float
)
  • DAO (Data Access Object)

Đây là component đại diện cho lớp hoặc interface như một đối tượng truy cập dữ liệu (DAO). DAO là thành phần chính của Room là chịu trách nhiệm trong việc định nghĩa các phương thức truy cập CSDL.

@Dao
interface ISchoolDAO {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertSchool(school: School)

    @Delete
    suspend fun deleteSchool(school: School)


    @Update
    suspend fun updateSchool(school: School)    

    @Transaction
    @Query("SELECT * FROM $SCHOOL_TABLE")
    fun getAllSchool(): Flow<List<SchoolAndStudent>>
}

5. Kết luận

Trên đây là phần giới thiệu cơ bản về Room database của mình.

Cám ơn các bạn đã đọc bài viết của mình.

Tham khảo: https://developer.android.com/training/data-storage/room#groovy

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.