Android Room LiveData Observer 未更新
Android Room LiveData Observer not updating
我有一个 Fragment
,里面有一个 RecyclerView
。我使用 ViewModel
保存 LiveData
以从 Room 数据库中显示,并尝试通过观察 ViewModel
中的数据来更新 RecyclerView
。但是当我打开片段时 Observer
只会被调用一次。我从与 Observer
不同的 Fragment
更新房间数据库。
无论我添加一个新的 Event
还是删除或更新一个,Observer
都不会被调用!我怎样才能正确调用 Observer
?我的错误在哪里?
片段
onViewCreated
中的代码在 onCreate
中不起作用,它 return 在行 val recyclerview = upcoming_recycler
上为空。
您还可以在 onViewCreated
的末尾看到我打开一个新片段,从中更新数据库。请注意 UpcomingFragment
与 EventEditFragment
!
的 FragmentLayout
不同
class UpcomingFragment : Fragment(R.layout.fragment_upcoming) {
private val clubDb by lazy {
ClubDatabase.getClubDatabase(requireContext().applicationContext)
}
private val eventAdapter = EventAdapter(null, this)
private val upcomingViewModel: UpcomingViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = upcoming_recycler
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
upcomingViewModel.eventsToShow.observe(viewLifecycleOwner, Observer { events ->
Log.d(TAG, "Live data changed in upcomingfragment!!!")
eventAdapter.setData(events.toTypedArray())
})
recyclerView.adapter = eventAdapter
// add a new Event
upcoming_fab.setOnClickListener {
parentFragmentManager.beginTransaction()
.replace(R.id.main_fragment_layout_overlay, EventEditFragment())
.addToBackStack(EVENT_EDIT_FRAGMENT)
.commit()
}
// and more stuff...
}
//the rest of the class
}
视图模型
class UpcomingViewModel(application: Application) : ViewModel() {
val eventsToShow: LiveData<List<Event>>
init {
val roundToDay = SimpleDateFormat("dd.MM.yyy", Locale.GERMAN)
var today = Date()
today = roundToDay.parse(roundToDay.format(today))!!
val tomorrow = Date(today.time + 86400000L)
eventsToShow = ClubDatabase.getClubDatabase(application.applicationContext).clubDao()
.getEventsByClubIdAfterDate(CURRENT_CLUB_ID, tomorrow)
}
}
事件适配器
class EventAdapter(
private var dataSet: Array<Event>?,
private val onEventItemClickListener: OnEventItemClickListener
) : RecyclerView.Adapter<EventAdapter.EventViewHolder>() {
class EventViewHolder(val view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.event_item_layout, parent, false)
return EventViewHolder(view)
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
// show the item & add onEventItemClickListener for updating
}
fun setData(new: Array<Event>) {
this.dataSet = new
this.notifyDataSetChanged()
}
override fun getItemCount(): Int {
return dataSet?.size ?: 0
}
}
数据库
@Database(
entities = [Event::class, Member::class, RequiredMembersForEvents::class, AttendedMembersForEvents::class],
version = 9,
exportSchema = false
)
@TypeConverters(Converters::class)
abstract class ClubDatabase : RoomDatabase() {
abstract fun clubDao(): ClubDao
companion object {
@Volatile
private var INSTANCE: ClubDatabase? = null
fun getClubDatabase(context: Context): ClubDatabase {
return INSTANCE ?: synchronized(this) {
val instance = INSTANCE
return if (instance != null) {
instance
} else {
Room.databaseBuilder(
context.applicationContext,
ClubDatabase::class.java,
"club-db"
)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build()
}
}
}
}
}
DAO
@Dao
interface ClubDao {
@Query("SELECT * FROM events WHERE clubId = :clubId AND dateTimeFrom > :date ORDER BY dateTimeFrom ASC")
fun getEventsByClubIdAfterDate(clubId: String, date: Date): LiveData<List<Event>>
// the rest of the DAO
}
检查您的数据库单例实现,因为那里的变量 INSTANCE - 始终为空。当你得到class的实例时,你应该在第一次设置它。否则,您的应用会处理数据库的不同实例 class.
可能这会导致问题,虽然对数据库进行了一些更改,但未触发 LiveData 对这些更改的观察器。
我有一个 Fragment
,里面有一个 RecyclerView
。我使用 ViewModel
保存 LiveData
以从 Room 数据库中显示,并尝试通过观察 ViewModel
中的数据来更新 RecyclerView
。但是当我打开片段时 Observer
只会被调用一次。我从与 Observer
不同的 Fragment
更新房间数据库。
无论我添加一个新的 Event
还是删除或更新一个,Observer
都不会被调用!我怎样才能正确调用 Observer
?我的错误在哪里?
片段
onViewCreated
中的代码在 onCreate
中不起作用,它 return 在行 val recyclerview = upcoming_recycler
上为空。
您还可以在 onViewCreated
的末尾看到我打开一个新片段,从中更新数据库。请注意 UpcomingFragment
与 EventEditFragment
!
FragmentLayout
不同
class UpcomingFragment : Fragment(R.layout.fragment_upcoming) {
private val clubDb by lazy {
ClubDatabase.getClubDatabase(requireContext().applicationContext)
}
private val eventAdapter = EventAdapter(null, this)
private val upcomingViewModel: UpcomingViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = upcoming_recycler
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
upcomingViewModel.eventsToShow.observe(viewLifecycleOwner, Observer { events ->
Log.d(TAG, "Live data changed in upcomingfragment!!!")
eventAdapter.setData(events.toTypedArray())
})
recyclerView.adapter = eventAdapter
// add a new Event
upcoming_fab.setOnClickListener {
parentFragmentManager.beginTransaction()
.replace(R.id.main_fragment_layout_overlay, EventEditFragment())
.addToBackStack(EVENT_EDIT_FRAGMENT)
.commit()
}
// and more stuff...
}
//the rest of the class
}
视图模型
class UpcomingViewModel(application: Application) : ViewModel() {
val eventsToShow: LiveData<List<Event>>
init {
val roundToDay = SimpleDateFormat("dd.MM.yyy", Locale.GERMAN)
var today = Date()
today = roundToDay.parse(roundToDay.format(today))!!
val tomorrow = Date(today.time + 86400000L)
eventsToShow = ClubDatabase.getClubDatabase(application.applicationContext).clubDao()
.getEventsByClubIdAfterDate(CURRENT_CLUB_ID, tomorrow)
}
}
事件适配器
class EventAdapter(
private var dataSet: Array<Event>?,
private val onEventItemClickListener: OnEventItemClickListener
) : RecyclerView.Adapter<EventAdapter.EventViewHolder>() {
class EventViewHolder(val view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.event_item_layout, parent, false)
return EventViewHolder(view)
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
// show the item & add onEventItemClickListener for updating
}
fun setData(new: Array<Event>) {
this.dataSet = new
this.notifyDataSetChanged()
}
override fun getItemCount(): Int {
return dataSet?.size ?: 0
}
}
数据库
@Database(
entities = [Event::class, Member::class, RequiredMembersForEvents::class, AttendedMembersForEvents::class],
version = 9,
exportSchema = false
)
@TypeConverters(Converters::class)
abstract class ClubDatabase : RoomDatabase() {
abstract fun clubDao(): ClubDao
companion object {
@Volatile
private var INSTANCE: ClubDatabase? = null
fun getClubDatabase(context: Context): ClubDatabase {
return INSTANCE ?: synchronized(this) {
val instance = INSTANCE
return if (instance != null) {
instance
} else {
Room.databaseBuilder(
context.applicationContext,
ClubDatabase::class.java,
"club-db"
)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build()
}
}
}
}
}
DAO
@Dao
interface ClubDao {
@Query("SELECT * FROM events WHERE clubId = :clubId AND dateTimeFrom > :date ORDER BY dateTimeFrom ASC")
fun getEventsByClubIdAfterDate(clubId: String, date: Date): LiveData<List<Event>>
// the rest of the DAO
}
检查您的数据库单例实现,因为那里的变量 INSTANCE - 始终为空。当你得到class的实例时,你应该在第一次设置它。否则,您的应用会处理数据库的不同实例 class.
可能这会导致问题,虽然对数据库进行了一些更改,但未触发 LiveData 对这些更改的观察器。