jetpack compose Room

1,294 阅读2分钟

配置

//file:build.gradle(Module)

plugins {
    ...
    id 'kotlin-kapt'
}

...

dependencies {
    ...
    implementation 'androidx.room:room-runtime:2.4.2'
    implementation "androidx.room:room-ktx:2.4.2"
    kapt 'androidx.room:room-compiler:2.4.2'

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"

    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
}

数据库配置

//创建数据实体类
@Entity(tableName = "details")
data class Detail(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    val id: Int? = null,
    var message: String = "",
    var date: String = "2021/1/1",
    var detailType: DetailType = DetailType()
)

//复杂数据
data class DetailType(
    val name: String = "无",
    val triad: Boolean = true
)

//由于数据库无法添加除了规定类型外的所有类型,要写一个转化器来指导数据库进行复杂数据的转化
class DetailTypeConverters {
    @TypeConverter
    fun stringToObject(value: String?): DetailType? {
        val it = object : TypeToken<DetailType>() {}.type
        return Gson().fromJson(value, it)
    }

    @TypeConverter
    fun objectToString(value: DetailType?): String? {
        val gson = Gson()
        return gson.toJson(value)
    }
}

@Dao
interface DetailDao {
    @Query("SELECT * FROM details")
    fun queryAll(): Flow<List<Detail>>

    @Insert
    fun insert(detail: Detail?)

    @Query("DELETE FROM details")
    fun deleteAll()

    @Update
    fun updata(detail: Detail)

    @Delete
    fun delete(detail: Detail)


    //[Detail::class]为你创建的数据实体类
    //@return Flow<List<Detail>> 配合 jetpack compose 可以在数据变化时自动更新ui
    @RawQuery(observedEntities = [Detail::class])
    fun execsql(query: SupportSQLiteQuery) : Flow<List<Detail>>
}

//@Database(entities = [Detail::class], version = 1)entities为数据类,数据结构变化时version要增加1
//@TypeConverters(DetailTypeConverters::class,...)指定复杂数据格式转换器,多个转换器之间用逗号隔开
@Database(entities = [Detail::class], version = 1)
@TypeConverters(DetailTypeConverters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun getDetailDao(): DetailDao
}

App

你可以创建一个继承于Application的应用类来长久持有数据库的引用,在程序的任何地方都可以用 App.db.getDetailDao()获取到数据库的Dao(注意:getDetailDao()根据你定义的接口名而定)

class App:Application() {
    companion object {
        lateinit var db: AppDatabase

        @SuppressLint("StaticFieldLeak")
        var sContext: Context? = null

    }

    override fun onCreate() {
        super.onCreate()
        sContext = this

        db = Room
            .databaseBuilder(sContext as App,AppDatabase::class.java,"db_details")
            .build()
    }
}

Activity

数据库的操作不能在ui线程进行,使用Thread {...}.star()对数据库进行操作

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val detailDao = App.db.getDetailDao()

        val details = detailDao.execsql(
                SimpleSQLiteQuery(
                    "SELECT * FROM details WHERE message='hello'", //获取messge为hello的数据
                    arrayOf()
                )
            ).asLiveData()
        setContent {
            val detailsState = details.observeAsState(arrayListOf())   //获取状态监听
            LazyColumn {
                item {
                    Button(onClick = {
                        val detail = Detail(
                            message = "hello",
                            detailType = DetailType("666", false),
                        )
                        Thread {
                            detailDao.insert(detail)
                        }.start()
                    }) {
                        Text("+1")
                    }
                }
                item {
                    Button(onClick = {
                        finish()
                    }) {
                        Text(text = "finish")
                    }
                }
                items(detailsState.value) { it ->
                    Row(
                        Modifier.fillMaxWidth()
                    ) {
                        Text(text = "${it.id} ${it.message}")
                        IconButton(onClick = {
                            Thread {
                                detailDao.delete(it)
                            }.start()
                        }) {
                            Icon(
                                imageVector = Icons.Default.Clear,
                                contentDescription = "删除"
                            )
                        }
                    }
                }
            }
        }
    }
}

参考文献

使用 Room 将数据保存到本地数据库  |  Android 开发者  |  Android Developers (google.cn)

Compose搭档 — Flow、Room_乐翁龙的博客-CSDN博客_flow room

kotlin - Android room rawquery issue - Stack Overflow