Android compose Room Sqlite 应用 (注入式)
1.添加room库
project build.gradle.kts
//pluginskotlin("plugin.serialization") version "2.1.0"id("androidx.room") version "2.7.1" apply false
app build.gradle.kts
//plugins kotlin("plugin.serialization")id("androidx.room")kotlin("kapt")
//dependencies
//roomvar 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")//injectimplementation("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")//serializationimplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
2.创建数据库
//Entities
@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
@Dao
interface BannerDao {@Insertsuspend fun insertAll(banners: List<BannerEntity>)@Query("SELECT * FROM banner")suspend fun getAll(): List<BannerEntity>
}@Dao
interface CategoryDao {@Insertsuspend fun insertAll(categories: List<CategoryEntity>)@Query("SELECT * FROM category")suspend fun getAll(): List<CategoryEntity>
}@Dao
interface ItemDao {@Insertsuspend 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 {@Insertsuspend fun insertAll(picUrls: List<PicUrlEntity>)@Query("SELECT * FROM pic_url WHERE itemId = :itemId")suspend fun getPicsByItemId(itemId: Int): List<PicUrlEntity>
}
//Databases
@Database(entities = [BannerEntity::class,CategoryEntity::class,ItemEntity::class,PicUrlEntity::class
], version = 1)
abstract class AppDatabase : RoomDatabase() {abstract fun bannerDao(): BannerDaoabstract fun categoryDao(): CategoryDaoabstract fun itemDao(): ItemDaoabstract fun picUrlDao(): PicUrlDaocompanion object {@Volatileprivate var INSTANCE: AppDatabase? = nullprivate 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()}}
}
//数据库文件
在绑定文件中。
3. 配置模块,定义 Application
val appModule = module {single { AppDatabase.getInstance(get()) }viewModelOf(::DashboardViewModel)
}
class OnlineShopApplication: Application() {override fun onCreate() {super.onCreate()startKoin {androidContext(this@OnlineShopApplication)modules(appModule)}}
}
在AndroidManifest.xml中添加application的使用代号
<applicationandroid: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"><activityandroid: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
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
data class DashboardState (val banners:List<BannerEntity> = emptyList(),val categories:List<CategoryEntity> = emptyList(),val itemWithPics:List<ItemWithPics> = emptyList(),
)
6.使用viewmodel
在@Compose中
// val isPreview = falseval viewModel = if (isPreview) injectPreviewModel() else koinViewModel()val mState by viewModel.mState.collectAsStateWithLifecycle()//使用时//mState.banners
@Composable
fun injectPreviewModel(): DashboardViewModel {val context = LocalContext.currentreturn remember {DashboardViewModel(AppDatabase.getInstance(context))}
}
7.当viewmodel中带有参数时。
//定义带有参数的viewmodel时class DetailViewModel(private val appDatabase: AppDatabase,private val param: Route.Detail
) : ViewModel() {}
在@Compose使用时
val viewModel =if (isPreview) injectPreviewModel(param) else koinViewModel { parameterSetOf(param)}val mState by viewModel.mState.collectAsStateWithLifecycle()