@Entity(tableName = "friends")
建立一张表,表名叫friends
@PrimaryKey @ColumnInfo(name = "id")
,将注释后面的属性设置成一个Column,并且指定这个属性是主键@ColumnInfo
该注释后面的属性将成为表中的一个Column属性friends
表的,就用注释@Ignore var XXXX
@Entity(tableName = "friends")
data class Friend (
@PrimaryKey @ColumnInfo(name = "id") val friendId: String
){
@ColumnInfo(name = "avator_url") var friendAvatorUrl = ""
@ColumnInfo(name = "name") var friendName = ""
}
@Dao
@Insert(onConflict = OnConflictStrategy.REPLACE)
冲突策略@Dao
interface FriendDao {
@Query("SELECT * FROM friends ORDER BY name")
fun getFriends():LiveData<List<Friend>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertFriend(friend: Friend): Long
@Delete
suspend fun deletedFriend(friend: Friend)
}
addFriend(friend: Friend)
,deleteFriend(friend: Friend)
class FriendRepository private constructor(
private val friendDao: FriendDao
){
//向表中添加一个friend
suspend fun addFriend(friend: Friend) = friendDao.insertFriend(friend)
//向表中删除一个friend
suspend fun deleteFriend(friend: Friend) = friendDao.deletedFriend(friend)
//获取表中的所有friend并返回 LiveData>
fun getFriends() = friendDao.getFriends()
companion object{
@Volatile private var instance: FriendRepository? = null
fun getInstance(friendDao: FriendDao) =
instance ?: synchronized(this){
instance ?: FriendRepository(friendDao).also { instance = it }
}
}
}
Friend
,还有的话往里添加@Database(entities = arrayOf(Friend::class), version = 1, exportSchema = false)
Room
需要有获取Dao
的抽象方法, 创建Repository
的时候才能从RoomDatabase
里面通过friendDao()
获取 //获取 Dao
abstract fun friendDao(): FriendDao
Context
,并且使用Room.databaseBuilder(context: Context, XxxRoomDatabase::class.java, "Xxx_database")
,后面两个参数分别是你的RoomDatabase
的类名,还有数据库的名字RoomDatabase
的Callback
,在协程中向数据库里放数据,放完后build()
一下Callback
里面的onCreate()
和onOpen()
方法,onCreate()
就只会在创建的时候回调一次,直到你删库跑路又回来重新创建。onOpen()
,就是每次打开app都会回调@Database(entities = arrayOf(Agenda::class, Friend::class, Plan::class),
version = 1,
exportSchema = false)
abstract class AppRoomDatabase : RoomDatabase() {
abstract fun friendDao(): FriendDao
companion object{
@Volatile
private var INSTANCE: AppRoomDatabase? = null
fun getInstance(
context: Context): AppRoomDatabase{
return INSTANCE ?: synchronized(this){
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
private fun buildDatabase(context: Context):AppRoomDatabase{
return Room.databaseBuilder(context, AppRoomDatabase::class.java, "app_database")
//让数据库一开始就有数据,覆写Callback()里的onCreate()或者onOpen()
.addCallback(object : RoomDatabase.Callback(){
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
//这里要操作数据库,不能在主线程中操作,我这里用的 Worker
/*val request = OneTimeWorkRequestBuilder().build()
WorkManager.getInstance(context).enqueue(request)
*/
}
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
//这里要操作数据库,不能在主线程中操作,我这里用的 Worker
/*val request = OneTimeWorkRequestBuilder().build()
WorkManager.getInstance(context).enqueue(request)
*/
}
}).build()
}
}
}
Repository
的引用,因为要获取数据List
insert(friend: Friend)
, 同样的不能在主线程访问,ViewModel里面当然在viewModelScope
里面访问class FriendListViewModel(
private val friendListRepository: FriendRepository
): ViewModel(){
var friends: LiveData<List<Friend>> = friendListRepository.getFriends()
fun insert(friend: Friend) = viewModelScope.launch {
friendListRepository.addFriend(friend)
}
}
class FriendListViewModelFactory(
private val repository: FriendRepository
): ViewModelProvider.NewInstanceFactory() {
@Suppress
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return FriendListViewModel(repository) as T
}
}
ViewModel
-> Repository
-> Dao
-> RoomDatabase
需要在Activity
或者Fragment
中创建ViewModel
,在这里,创建ViewModel
我选择通过ViewModelFactory
。思路 是这样的: 创建ViewModel
,ViewModel
需要获取数据需要通过Repository
,ViewModel
中需要有Repository
的引用,而Repository
要获取数据库数据需要通过Dao
接口,Repository
又需要Dao
的引用,要获取Dao
,那么需要有RoomDatabase
来提供Dao
给Repository
。所以,逆向就能构建出可以和数据库联系起来的ViewModel
AppRoomDatabase
的实例,它的FriendDao()
方法返回FriendDao
,传入FriendRepository(friendDao : FriendDao)
,获得一个FriendRepository
实例private fun getFriendRepository(context: Context) : FriendRepository{
return FriendRepository.getInstance(
AppRoomDatabase.getInstance(context).friendDao()
)
}
Repository
传入ViewModelFactory()
fun provideFriendListViewModelFactory(context: Context): FriendListViewModelFactory{
//调用上面的那个方法
var repository = getFriendRepository(context)
return FriendListViewModelFactory(repository)
}
将上面两个方法写在了实用类里面,参照的SunFlower
object InjectorUtils {
private fun getFriendRepository(context: Context) : FriendRepository{
return FriendRepository.getInstance(
AppRoomDatabase.getInstance(context).friendDao()
)
}
fun provideFriendListViewModelFactory(context: Context): FriendListViewModelFactory{
var repository = getFriendRepository(context)
return FriendListViewModelFactory(repository)
}
}
Activity
或者Fragment
中创建ViewModel
直接调用InjectorUtils
的provideFriendListViewModelFactory(context: Context)
,获取了Factory
之后直接create
就可以了
class FriendFragment : Fragment() {
private lateinit var friendListViewModel: FriendListViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//重点在这里,其他不重要
friendListViewModel = InjectorUtils
.provideFriendListViewModelFactory(requireContext())
.create(FriendListViewModel::class.java)
return FragmentFriendBinding.inflate(inflater, container,
false).root
}
}