我正在尝试学习如何重写我的房间数据库(dao、存储库、viewmodel)以提高效率。我没有使用过这些中的任何一个,而且我很难找到可以作为基础的资源,因为他们中的许多人要么不使用存储库(所以我开始认为我已经不必要地实现了它)或者他们正在使用刀柄,我对要学习的新东西有点不知所措。
我应该如何实现存储库和视图模型以在其中包含流和协程?
好吧,你的问题很笼统,但我会尽力回答,我想你至少对协程、流和 Hilt 有基本的了解,如果你没有,没关系,至少尝试学习一些东西新的,我尽量让它简单。
场景:
假设有一个简单的应用程序向用户显示书籍信息,用户可以将任何书籍添加到收藏夹,从收藏夹中删除它们,并有一个屏幕来显示收藏的书籍。
我们有一个名为 Book 的简单实体类:
@Entity
data class Book(
@PrimaryKey
val ispn: String
val title: String,
val description: String,
val pages: Int
)
现在,让我们创建一个带有 Flow 和挂起函数的 DAO 接口:
@Dao
interface FavoriteBooksDao {
@Query("SELECT * FROM book")
fun selectAll(): Flow<List<Book>> // No need to add suspend keyword, because it returns Flow, flows already uses coroutines.
@Insert
suspend fun insert(book: Book) // Simply, add suspend keyword to the function, to make it work with coroutines.
@Delete
suspend fun delete(book: Book) // Simply, add suspend keyword to the function, to make it work with coroutines.
}
说明:
我们有3个功能:
selectAll()
:检索最喜欢的书的列表。
insert()
:插入一本新书。
delete()
:删除一本书。
要使插入和删除与协程一起工作,请为这两个函数添加
suspend
关键字。对于selectAll()
函数,它返回一个流,你可以把它看作是对LiveData
的替代,这样我们就可以在插入或删除新书时观察book
表上的变化,selectAll()
将在插入/删除后发出一个新列表,允许您更新您的 UI。请注意,selectAll()
不是挂起函数,因为它返回一个流,流已经使用协程,所以我们不需要 suspend
关键字。
现在让我们创建存储库:
class FavoriteBooksRepository @Inject constructor(
private val dao: FavoriteBooksDao
) {
fun getAll() = dao.selectAll() //Non-suspending function
suspend fun add(book: Book) = dao.insert(book) //suspending function
suspend fun remove(book: Book) = dao.delete(book) //suspending function
}
说明:
现在,您需要存储库中的 DAO 实例,使用 Hilt 注入它。
您在存储库中有 3 个函数将调用 DAO 函数,您将有
add()
和 remove()
作为挂起函数,因为您在 DAO 中声明 insert()
和 delete()
作为挂起函数,而 getAll()
是不要在你的 DAO 中像 selectAll()
那样暂停,因为它会返回一个流程,如前所述。
最后,让我们实现ViewModel:
@HiltViewModel
class FavoriteBooksViewModel @Inject constructor(
private val repository: FavoriteBooksRepository
): ViewModel() {
// This is a mutable state flow that will be used internally in the viewmodel, empty list is given as initial value.
private val _favoriteBooks = MutableStateFlow(emptyList<Book>())
//Immutable state flow that you expose to your UI
val favoriteBooks = _favoriteBooks.asStateFlow()
init {
getFavoriteBooks()
}
/**
* This function is used to get all the books from the database, and update the value of favoriteBooks.
* 1. viewModelScope.launch is used to launch a coroutine within the viewModel lifecycle.
* 2. repository.getAll() is used to get all the books from the database.
* 3. flowOn(Dispatchers.IO) is used to change the dispatcher of the flow to IO, which is optimal for IO operations, and does not block the main thread.
* 4. collect is a suspending function used to collect the flow of books list, and assign the value to favoriteBooks.
* 5. each time the flow emits a new value, the collect function will be called with the list of books.
*/
fun getFavoriteBooks() {
viewModelScope.launch { //this: CoroutineScope
repository.getAll().flowOn(Dispatchers.IO).collect { books: List<Book> ->
_favoriteBooks.update { books }
}
}
}
/**
* This function is used to add a book to the database.
* 1. viewModelScope.launch is used to launch a coroutine within the viewModel lifecycle.
* 2. Dispatchers.IO is used to change the dispatcher of the coroutine to IO, which is optimal for IO operations, and does not block the main thread.
* 3. repository.add(book) is used to add the book to the database.
*/
fun addBook(book: Book) {
viewModelScope.launch(Dispatchers.IO) { //this: CoroutineScope
repository.add(book)
}
}
/**
* This function is used to remove a book from the database.
* 1. viewModelScope.launch is used to launch a coroutine within the viewModel lifecycle.
* 2. Dispatchers.IO is used to change the dispatcher of the coroutine to IO, which is optimal for IO operations, and does not block the main thread.
* 3. repository.remove(book) is used to remove the book from the database.
*/
fun removeBook(book: Book) {
viewModelScope.launch(Dispatchers.IO) { //this: CoroutineScope
repository.remove(book)
}
}
}
说明:
现在,您需要 viewModel 中的 Repository 实例,使用 Hilt 注入它。
我添加了文档,分别描述了所有的工作和功能,尽可能清楚,还要注意功能不是挂起的,因为我们启动了一个
viewModelScope
协程,就足够了,不需要标记这些功能作为暂停。
这就是您在 Room 数据库、存储库和视图模型中将协程和流与您的应用程序集成的方式。随着您了解更多,您可以对流和协程执行更高级的操作,以使您的应用程序更加健壮和高效。你可以根据你的应用需求添加更多的操作和代码,我尽量用最简单的格式来表示。
最后,感谢您花时间阅读本文,希望对您有所帮助。