1.添加room库
project build.gradle.kts
Kotlin
//plugins
kotlin("plugin.serialization") version "2.1.0"
id("androidx.room") version "2.7.1" apply false
app build.gradle.kts
Kotlin
//plugins
kotlin("plugin.serialization")
id("androidx.room")
kotlin("kapt")
Kotlin
//dependencies
//room
var room_version = "2.7.1"
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-runtime:$room_version")
kapt("androidx.room:room-compiler:$room_version")
//inject
implementation("io.insert-koin:koin-android:4.0.3")
implementation("io.insert-koin:koin-androidx-compose:4.0.3")
implementation("io.insert-koin:koin-androidx-compose-navigation:4.0.3")
//serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
2.创建数据库
//Entities
Kotlin
@Entity(tableName = "banner")
data class BannerEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val url: String
)
@Entity(tableName = "category")
data class CategoryEntity(
@PrimaryKey val id: Int,
val title: String
)
@Entity(tableName = "item")
data class ItemEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val title: String,
val description: String,
val price: Int,
val rating: Double,
val showRecommended: Boolean,
val categoryId: Int
)
@Entity(tableName = "pic_url")
data class PicUrlEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val itemId: Int,
val url: String
)
data class ItemWithPics(
@Embedded val item: ItemEntity,
@Relation(
parentColumn = "id",
entityColumn = "itemId"
)
val pics: List<PicUrlEntity>
)
data class ItemWithCategory(
@Embedded val item: ItemEntity,
@Relation(
parentColumn = "categoryId",
entityColumn = "id"
)
val category: CategoryEntity
)
data class ItemFull(
@Embedded val item: ItemEntity,
@Relation(
parentColumn = "id",
entityColumn = "itemId"
)
val pics: List<PicUrlEntity>,
@Relation(
parentColumn = "categoryId",
entityColumn = "id"
)
val category: CategoryEntity
)
//Daoes
Kotlin
@Dao
interface BannerDao {
@Insert
suspend fun insertAll(banners: List<BannerEntity>)
@Query("SELECT * FROM banner")
suspend fun getAll(): List<BannerEntity>
}
@Dao
interface CategoryDao {
@Insert
suspend fun insertAll(categories: List<CategoryEntity>)
@Query("SELECT * FROM category")
suspend fun getAll(): List<CategoryEntity>
}
@Dao
interface ItemDao {
@Insert
suspend fun insertAll(items: List<ItemEntity>)
@Transaction
@Query("SELECT * FROM item")
suspend fun getItemsWithPics(): List<ItemWithPics>
@Transaction
@Query("SELECT * FROM item WHERE showRecommended = 1")
suspend fun getRecommendedItems(): List<ItemWithPics>
@Transaction
@Query("SELECT * FROM item WHERE categoryId = :categoryId")
suspend fun getItemsByCategory(categoryId: Int): List<ItemWithPics>
@Transaction
@Query("SELECT * FROM item")
suspend fun getFullItemData(): List<ItemFull>
}
@Dao
interface PicUrlDao {
@Insert
suspend fun insertAll(picUrls: List<PicUrlEntity>)
@Query("SELECT * FROM pic_url WHERE itemId = :itemId")
suspend fun getPicsByItemId(itemId: Int): List<PicUrlEntity>
}
//Databases
Kotlin
@Database(entities = [
BannerEntity::class,
CategoryEntity::class,
ItemEntity::class,
PicUrlEntity::class
], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun bannerDao(): BannerDao
abstract fun categoryDao(): CategoryDao
abstract fun itemDao(): ItemDao
abstract fun picUrlDao(): PicUrlDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
private const val DATABASE_NAME = "database.db"
fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
DATABASE_NAME
).createFromAsset(DATABASE_NAME)
.build()
}
}
}
//数据库文件
在绑定文件中。
- 配置模块,定义 Application
Kotlin
val appModule = module {
single { AppDatabase.getInstance(get()) }
viewModelOf(::DashboardViewModel)
}
Kotlin
class OnlineShopApplication: Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@OnlineShopApplication)
modules(appModule)
}
}
}
在AndroidManifest.xml中添加application的使用代号
Kotlin
<application
android:name=".OnlineShopApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.OnlineShopApp"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.OnlineShopApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
4.创建DashboardViewModel
Kotlin
class DashboardViewModel(
private val appDatabase: AppDatabase
): ViewModel() {
private val _mState = MutableStateFlow(DashboardState())
val mState = _mState.onStart {
initBanners()
initCategories()
initItemWithPics()
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
_mState.value
)
private fun initBanners(){
viewModelScope.launch {
val bannerEntities = appDatabase.bannerDao().getAll()
_mState.update {
it.copy(banners = bannerEntities)
}
}
}
private fun initCategories(){
viewModelScope.launch {
val categoryEntities = appDatabase.categoryDao().getAll()
_mState.update {
it.copy(categories = categoryEntities)
}
}
}
private fun initItemWithPics(){
viewModelScope.launch {
val recommandItems = appDatabase.itemDao().getRecommendedItems()
_mState.update {
it.copy(itemWithPics = recommandItems)
}
}
}
}
5.创建DashboardState
Kotlin
data class DashboardState (
val banners:List<BannerEntity> = emptyList(),
val categories:List<CategoryEntity> = emptyList(),
val itemWithPics:List<ItemWithPics> = emptyList(),
)
6.使用viewmodel
在@Compose中
Kotlin
// val isPreview = false
val viewModel = if (isPreview) injectPreviewModel() else koinViewModel()
val mState by viewModel.mState.collectAsStateWithLifecycle()
//使用时
//mState.banners
Kotlin
@Composable
fun injectPreviewModel(): DashboardViewModel {
val context = LocalContext.current
return remember {
DashboardViewModel(
AppDatabase.getInstance(context)
)
}
}
7.当viewmodel中带有参数时。
Kotlin
//定义带有参数的viewmodel时
class DetailViewModel(
private val appDatabase: AppDatabase,
private val param: Route.Detail
) : ViewModel() {
}
在@Compose使用时
Kotlin
val viewModel =
if (isPreview) injectPreviewModel(param) else koinViewModel { parameterSetOf(param)}
val mState by viewModel.mState.collectAsStateWithLifecycle()