从视图模型中删除 UI 元素检查 table 是否为空
Remove UI element checking if table is empty from the viewmodel
好的,我会尽量保持简单。我正在编写一个应用程序,其中一个片段包含一个 recyclerview,它显示 Room table 内的元素。当 table 为空时,我应该显示一个占位符。
我对 MVVM 很陌生,但我尝试遵循的方法是将占位符添加到布局(一个简单的文本视图),如果 table 不为空,则将其从布局中删除。问题是,每次尝试确定 table 是否为空都没有用。我试过的是:
- 在 DAO 中有一个简单的查询(下面的代码),并在视图模型中调用它。然后从视图模型中我使用片段本身中的函数。由于我认为的执行时间,这种方法不起作用,因为 viewmodel 函数使用协程正常工作
- 尝试使用 recyclerview 适配器及其 getItemCount 方法,但它总是 return 0
所以基本上我很努力地在数据库为空时简单地从布局中删除文本视图,同时避免破坏 MVVM 原则。这是一些有用的代码
DAO函数
@Query("SELECT * FROM Event LIMIT 1")
fun getAnyEvent(): EventResult?
ViewModel 函数
fun getAnyEvent() = viewModelScope.launch(Dispatchers.Default) {
eventDao.getAnyEvent()
}
第一个无效的方法
if (homeViewModel.getAnyEvent() != null) {
val homeMain: LinearLayout = v.findViewById(R.id.homeMain)
val placeholder: TextView = v.findViewById(R.id.noEvents)
homeMain.removeView(placeholder)
}
适配器
class EventAdapter internal constructor(context: Context) : RecyclerView.Adapter<EventAdapter.EventViewHolder>() {
private var events = emptyList<EventResult>() // Cached copy of events
private val appContext = context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
return EventViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.event_row, parent, false))
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val current = events[position]
holder.setUpView(event = current)
}
inner class EventViewHolder (view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
private val favoriteButton: ImageView = view.favoriteButton
private val eventPerson: TextView = view.eventPerson
private val eventDate: TextView = view.eventDate
private val eventYears: TextView = view.eventYears
init {
view.setOnClickListener(this)
}
// Set every necessary text and click action in each row
fun setUpView(event: EventResult?) {
val personName = event?.name + " " + event?.surname
val formatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
val nextDate = event?.nextDate?.format(formatter)
val nextAge = appContext.getString(R.string.next_age_years) + ": " + (event?.nextDate?.year?.minus(event.originalDate.year)).toString()
eventPerson.text = personName
eventDate.text = nextDate
eventYears.text = nextAge
override fun onClick(v: View?) {
println("test")
}
}
internal fun setEvents(events: List<EventResult>) {
this.events = events
notifyDataSetChanged()
}
override fun getItemCount() = events.size
}
我应该使用什么方法?使用这种模式我做错了什么?
作为旁注,recyclerview 有效,我已经在使用实时数据来正确观察变化。
看来你只有一个需要——在你的片段中知道你的数据库查询是否 return 0 条或更多条记录。您是否尝试过为此使用 LiveData(没有协程)? (你提到了,但不清楚)
- 您的 DAO 应该 return LiveData 值。通过这个房间,“开箱即用”将以在线模式(当然,在后台线程中)获取您的 ViewModel 实际查询结果。
fun getAnyEvent(): LiveData<List<EventResult>>
- 在您的 ViewModel 中,您也可以使用 LiveData 声明字段
val eventResult: LiveData<List<EventResult>> = eventDao.getAnyEvent()
在你的片段中,你只需观察你的 eventResult,你可以根据列表大小用你的 UI 做任何你想做的事(如果它是 0,然后删除你的视图存根)
homeViewModel.eventResult.observe(viewLifecycleOwner, Observer { eventList -> yourAdapter.setEvents(eventList)})
Here 是 Google 的 Codelab,包含所有这些东西,例如
好的,我会尽量保持简单。我正在编写一个应用程序,其中一个片段包含一个 recyclerview,它显示 Room table 内的元素。当 table 为空时,我应该显示一个占位符。
我对 MVVM 很陌生,但我尝试遵循的方法是将占位符添加到布局(一个简单的文本视图),如果 table 不为空,则将其从布局中删除。问题是,每次尝试确定 table 是否为空都没有用。我试过的是:
- 在 DAO 中有一个简单的查询(下面的代码),并在视图模型中调用它。然后从视图模型中我使用片段本身中的函数。由于我认为的执行时间,这种方法不起作用,因为 viewmodel 函数使用协程正常工作
- 尝试使用 recyclerview 适配器及其 getItemCount 方法,但它总是 return 0
所以基本上我很努力地在数据库为空时简单地从布局中删除文本视图,同时避免破坏 MVVM 原则。这是一些有用的代码
DAO函数
@Query("SELECT * FROM Event LIMIT 1")
fun getAnyEvent(): EventResult?
ViewModel 函数
fun getAnyEvent() = viewModelScope.launch(Dispatchers.Default) {
eventDao.getAnyEvent()
}
第一个无效的方法
if (homeViewModel.getAnyEvent() != null) {
val homeMain: LinearLayout = v.findViewById(R.id.homeMain)
val placeholder: TextView = v.findViewById(R.id.noEvents)
homeMain.removeView(placeholder)
}
适配器
class EventAdapter internal constructor(context: Context) : RecyclerView.Adapter<EventAdapter.EventViewHolder>() {
private var events = emptyList<EventResult>() // Cached copy of events
private val appContext = context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
return EventViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.event_row, parent, false))
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val current = events[position]
holder.setUpView(event = current)
}
inner class EventViewHolder (view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
private val favoriteButton: ImageView = view.favoriteButton
private val eventPerson: TextView = view.eventPerson
private val eventDate: TextView = view.eventDate
private val eventYears: TextView = view.eventYears
init {
view.setOnClickListener(this)
}
// Set every necessary text and click action in each row
fun setUpView(event: EventResult?) {
val personName = event?.name + " " + event?.surname
val formatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
val nextDate = event?.nextDate?.format(formatter)
val nextAge = appContext.getString(R.string.next_age_years) + ": " + (event?.nextDate?.year?.minus(event.originalDate.year)).toString()
eventPerson.text = personName
eventDate.text = nextDate
eventYears.text = nextAge
override fun onClick(v: View?) {
println("test")
}
}
internal fun setEvents(events: List<EventResult>) {
this.events = events
notifyDataSetChanged()
}
override fun getItemCount() = events.size
}
我应该使用什么方法?使用这种模式我做错了什么? 作为旁注,recyclerview 有效,我已经在使用实时数据来正确观察变化。
看来你只有一个需要——在你的片段中知道你的数据库查询是否 return 0 条或更多条记录。您是否尝试过为此使用 LiveData(没有协程)? (你提到了,但不清楚)
- 您的 DAO 应该 return LiveData 值。通过这个房间,“开箱即用”将以在线模式(当然,在后台线程中)获取您的 ViewModel 实际查询结果。
fun getAnyEvent(): LiveData<List<EventResult>>
- 在您的 ViewModel 中,您也可以使用 LiveData 声明字段
val eventResult: LiveData<List<EventResult>> = eventDao.getAnyEvent()
在你的片段中,你只需观察你的 eventResult,你可以根据列表大小用你的 UI 做任何你想做的事(如果它是 0,然后删除你的视图存根)
homeViewModel.eventResult.observe(viewLifecycleOwner, Observer { eventList -> yourAdapter.setEvents(eventList)})
Here 是 Google 的 Codelab,包含所有这些东西,例如