Sqa*_*Sqa 2 android mvvm android-room kotlin-coroutines
我正在尝试学习如何重写我的房间数据库(dao、存储库、视图模型),以便它更加高效。我没有使用过其中任何一个,而且我很难找到可以依赖的资源,因为它们中的许多人要么不使用存储库(所以我开始认为我不必要地实现了它),要么他们正在使用刀柄,而我对要学习的新东西有点不知所措。
我应该如何实现存储库和视图模型以在内部包含流程和协程?
Abd*_*aml 16
好吧,你的问题很笼统,但我会尽力回答,我想你至少有协程、流程和 Hilt 的基本知识,如果没有,没问题,至少尝试学习一些新的东西,我尽量让它变得简单。
设想:
假设有一个简单的应用程序向用户显示书籍信息,用户可以将任何书籍添加到收藏夹,从收藏夹中删除它们,并有一个屏幕来显示收藏夹的书籍。
我们有一个简单的实体类,名为 Book:
@Entity
data class Book(
@PrimaryKey
val ispn: String
val title: String,
val description: String,
val pages: Int
)
Run Code Online (Sandbox Code Playgroud)
现在,让我们创建一个带有 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.
}
Run Code Online (Sandbox Code Playgroud)
解释:
我们有 3 个功能:
selectAll():检索最喜欢的书籍列表。
insert():插入新书。
delete():删除一本书。
要使插入和删除与协程一起使用,请suspend为这两个函数添加关键字。对于该selectAll()函数,它返回一个流,您可以将其视为 的替代品,这允许我们在插入或删除新书时LiveData观察表上的变化,在插入/删除后会发出一个新列表,从而允许您更新您的用户界面。请注意,这不是一个挂起函数,因为它返回一个流,流已经使用协程,所以我们不需要关键字。bookselectAll()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
}
Run Code Online (Sandbox Code Playgroud)
解释:
现在,您需要存储库中的 DAO 实例,使用 Hilt 注入它。
您在存储库中有 3 个函数,它们将调用 DAO 函数,您将拥有add()和remove()作为您在 DAO 中声明的挂起函数,insert()并且delete()作为 DAO 中的挂起函数,并且getAll()不会像selectAll()DAO 中那样挂起,因为它返回一个流,如前所述。
最后,让我们实现 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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
解释:
现在,您的 viewModel 中需要 Repository 实例,使用 Hilt 注入它。
我添加了单独描述所有工作和功能的文档,以尽可能清楚地说明,还要注意这些功能没有挂起,因为我们正在启动一个viewModelScope协程,这就足够了,不需要将这些功能标记为挂起。
这就是将协程和流与 Room 数据库、存储库和 viewModel 中的应用程序集成的方式。随着您了解更多,您可以对流和协程执行更高级的操作,以使您的应用程序更加健壮和高效。你可以根据你的应用需求添加更多的操作和代码,我尝试用最简单的格式来表示。
最后,感谢您在百忙之中阅读本文,希望对您有所帮助。
| 归档时间: |
|
| 查看次数: |
3221 次 |
| 最近记录: |