android - 如何使用 Room 在片段上更新 Livedata 对象?
问题描述
我对 MVVM 架构还很陌生,我有点困惑,为什么我似乎无法让 Livedata 对象更新到片段中的 recyclerview 中。在整个应用程序的各个位置使用 Log,我发现 sqlite 表正在更新,它只是不显示数据。
这是一个简单的笔记应用程序,我现在只是试图显示 sqlite 表中的标题。我可以在以后担心其余的事情。
任何帮助表示赞赏,我是房间的新手(一般是 sqlite),所以很多代码都是基于Room With a View教程。
如有必要,我可以提供更多代码,我只是想让它尽可能简单,以便有人查看!
标题片段
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class TitlesFragment : Fragment(){
private lateinit var noteViewModel: NoteViewModel
private lateinit var note: Note
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_titles, container, false)
val adapter = this.context?.let { NoteListAdapter(it) }
noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)
noteViewModel.allNotes.observe(viewLifecycleOwner, Observer { notes ->
notes?.let { adapter?.setNotes(it) }
})
val recyclerView = rootView.findViewById< RecyclerView>(R.id.titlesrecyclerview) as RecyclerView
recyclerView.layoutManager = LinearLayoutManager(activity)
recyclerView.adapter = this.context?.let { NoteListAdapter(it) }
return rootView
}
fun receiveNote(note: Note) {
this.note = note
noteViewModel.insert(this.note)
}
}
笔记列表适配器
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
class NoteListAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<NoteListAdapter.NoteViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var notes = emptyList<Note>()
inner class NoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val noteItemView: TextView = itemView.findViewById(R.id.title_box)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
val itemView = inflater.inflate(R.layout.fragment_titles, parent, false)
return NoteViewHolder(itemView)
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
val current = notes[position]
holder.noteItemView.text = current.note
}
internal fun setNotes(notes: List<Note>) {
this.notes = notes
notifyDataSetChanged()
}
override fun getItemCount() = notes.size
}
NoteViewModel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class NoteViewModel (application: Application) : AndroidViewModel(application) {
private val repository: NoteRepository
val allNotes: LiveData<List<Note>>
init {
val notesDao = NoteDatabase.getDatabase(application, viewModelScope).noteDao()
repository = NoteRepository(notesDao)
allNotes = repository.allNotes
}
fun insert(note: Note) = viewModelScope.launch(Dispatchers.IO) {
repository.insert(note)
}
}
注意数据库
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Database(entities = arrayOf(Note::class), version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null
fun getDatabase(context: Context, scope: CoroutineScope): NoteDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDatabase::class.java,
"note_database"
).addCallback(NoteDatabaseCallback(scope)).build()
INSTANCE = instance
return instance
}
}
}
private class NoteDatabaseCallback(
private val scope: CoroutineScope) : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
INSTANCE?.let { database ->
scope.launch {
populateDatabase(database.noteDao())
}
}
}
suspend fun populateDatabase(noteDao: NoteDao) {
noteDao.deleteAll()
var note = Note("test1", "hello")
noteDao.insert(note)
note = Note("test2", "world")
noteDao.insert(note)
}
}
}
注意存储库
import androidx.lifecycle.LiveData
class NoteRepository(private val noteDao: NoteDao) {
val allNotes: LiveData<List<Note>> = noteDao.getAllNotes()
suspend fun insert(note: Note) {
noteDao.insert(note)
}
}
笔记道
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
@Dao
interface NoteDao {
@Query("SELECT * from note_table")
fun getAllNotes(): LiveData<List<Note>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(note: Note)
@Query("DELETE FROM note_table")
suspend fun deleteAll()
}
解决方案
看完后onCreateView()
你有:
val adapter = this.context?.let { NoteListAdapter(it) }
并且观察者正在尝试相应地更新:
noteViewModel.allNotes.observe(viewLifecycleOwner, Observer { notes ->
notes?.let { adapter?.setNotes(it) }
})
但是,您要在以下位置设置新适配器:
recyclerView.adapter = this.context?.let { NoteListAdapter(it) }
因此它不会填充正确的适配器,因此请考虑切换到实际adapter
并删除新分配。
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView inflater.inflate(R.layout.fragment_titles, container, false)
noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)
val adapter = NoteListAdapter(requireContext())
noteViewModel.allNotes.observe(viewLifecycleOwner, Observer { notes ->
notes?.let { adapter.setNotes(it) }
})
val recyclerView = rootView.findViewById< RecyclerView>(R.id.titlesrecyclerview) as RecyclerView
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = adapter
return rootView
}
推荐阅读
- r - 使用R中的for循环填充要列出的数据框
- python-3.x - 检查两个列表中的用户名
- hyper-v - 有什么方法可以在 Windows 的 VT-x 上运行 Docker?
- java - 如何从 Java 调用 tabula (JAR)?
- spring - Spring Boot Actuator 在一个请求中返回所有指标
- javascript - 构造函数不返回方法
- spring-boot - Spring boot2,Mysql UTF-8 编码不起作用
- python - 无法获取 URL https://pypi.python.org/simple/xlrd/
- javascript - 获取 Facebook AR 中 3d 对象的位置并通过脚本更改它们
- netsuite - 通过传递国家代码获取 NetSuite SuiteScript 2.0 中国家列表的内部 ID