【发布时间】:2019-07-26 14:27:46
【问题描述】:
我是 Kotlin/Android 开发的新手,我正在尝试找出更新 Room 数据库中数据的最佳方法。在学习了一些教程之后,我目前的架构如下所示:
带有表和 DAO 的房间数据库 -> 存储库 -> ViewModel -> 活动
因此该活动有一个 ViewModel 调用存储库,进而更新数据库。
活动的 ViewModel 有一个对象的 LiveData 列表(还有一个工厂来创建 ViewModel,但这只是为了允许传入 bookId):
class ViewBookViewModel(application: Application, bookId: Int) : AndroidViewModel(application) {
private val repository: AppRepository
internal val flashCards: LiveData<List<FlashCard>>
init {
val flashCardDao = AppDatabase.getDatabase(application, viewModelScope).flashCardDao()
val bookDao = AppDatabase.getDatabase(application, viewModelScope).bookDao()
repository = AppRepository(flashCardDao, bookDao)
flashCards = flashCardDao.getByBookId(bookId)
}
fun insert(flashCard: FlashCard) = viewModelScope.launch(Dispatchers.IO){
repository.insert(flashCard)
}
fun setIsFavorited(cardUid: Long, favorited: Boolean) = viewModelScope.launch(Dispatchers.IO) {
repository.setIsFavorited(cardUid, favorited)
}
}
//The actual query that gets called eventually
@Query("UPDATE flashcard SET is_favorited = :favorited WHERE uid LIKE :cardUid")
fun setFavorited(cardUid: Long, favorited: Boolean)
Activity 设置了 viewModel 并在
上创建了一个观察者class ViewBookActivity : AppCompatActivity() {
private lateinit var flashCards: LiveData<List<FlashCard>>
private var layoutManager: RecyclerView.LayoutManager? = null
private lateinit var viewModel: ViewBookViewModel
private var bookId: Int = 0
private lateinit var bookTitle: String
override fun onCreate(savedInstanceState: Bundle?) {
...
bookId = intent.extras["bookId"] as Int
bookTitle = intent.extras["bookTitle"].toString()
layoutManager = LinearLayoutManager(this)
flashCardRecyclerView.layoutManager = layoutManager
viewModel = ViewModelProviders.of(this, ViewBookViewModelFactory(application, bookId as Int)).get(ViewBookViewModel::class.java)
flashCards = viewModel.flashCards
flashCards.observe(this, Observer { flashCards:List<FlashCard> ->
flashCardRecyclerView.adapter = FlashCardRecyclerAdapter(flashCards, viewModel)
})
}
}
最后,我有一个自定义的RecyclerAdapter,这是我遇到麻烦的地方。我进行了设置,以便当用户点击闪存卡上的“收藏夹”按钮时,它会更新数据库。但是,这也会导致 Activity “刷新”,滚动到顶部。我认为这是因为它正在观察 LiveData,并且该数据正在被更改。
带有 ViewHolder 代码的自定义 RecylcerAdapter(剥离不相关的代码):
class FlashCardRecyclerAdapter(val flashCards: List<FlashCard>, val viewModel: ViewBookViewModel) : RecyclerView.Adapter<FlashCardRecyclerAdapter.FlashCardViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlashCardViewHolder {
val v: View = LayoutInflater
.from(parent.context)
.inflate(R.layout.flash_card, parent, false)
return FlashCardViewHolder(v)
}
override fun onBindViewHolder(holder: FlashCardViewHolder, position: Int) {
val card = flashCards[position]
holder.isFavorited = card.isFavorited
holder.uid = card.uid
holder.modifyFavoriteButtonImage(holder.isFavorited)
}
override fun getItemCount(): Int {
return flashCards.size
}
inner class FlashCardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var mFavorited: Button
var frontShowing: Boolean
var isFavorited: Boolean = false
var uid: Long = 0
init {
mFavorited = itemView.findViewById(R.id.favoriteButton)
mFavorited.setOnClickListener { _ ->
isFavorited = !isFavorited
viewModel.setIsFavorited(uid, isFavorited) // Here is the database call
modifyFavoriteButtonImage(isFavorited)
}
}
fun modifyFavoriteButtonImage(isFavorited: Boolean){
// Code removed, just updates the image to be a filled/empty star based on favorited status
}
}
我觉得我可能做错了什么,因为将 ViewModel 传递到 recycler 适配器以更新数据库似乎不正确。在这种情况下我应该使用一种模式,还是应该将代码更改为不使用 LiveData?任何帮助将不胜感激。
【问题讨论】:
-
你不应该在 Observer 中分配 recyclerview 适配器,你应该只将你的闪存卡更新为一个数组。
-
您的架构理念是正确的:
Room Database with tables and DAOs -> Repository -> ViewModel -> Activity -
嗨,OP,看看我的回答,看看是否有帮助,如果您有任何问题或希望我解释,请随时告诉我:D
标签: android kotlin android-room