我正在尝试用Kotlin编写一个基本的Todo列表,但想使用推荐的最佳实践和Android体系结构组件。至此,我已经建立了基本的体系结构,并在数据库中存储了一个RecyclerView项目列表,左侧带有一个复选框,右侧是一个描述。到目前为止,当添加新数据时(通过浮动操作按钮),列表会自动更新。现在,我想每当单击特定项目的复选框时立即更新记录。
我无法弄清楚如何或在何处设置复选框侦听器,以将检查状态和项目ID传递给ViewModel以便更新数据库中的数据。我考虑过直接在适配器内部定义侦听器,但是后来找不到任何方法来调用ViewModel的update方法。但是,如果我在片段中设置了侦听器并将其传递给适配器,则找不到找到该项目ID的方法。
这是我当前的片段:
class ChecklistFragment : Fragment() {
private lateinit var checklistViewModel: ChecklistViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_checklist, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Set up RecyclerView
items_list.layoutManager = LinearLayoutManager(activity)
val adapter = ToDoItemAdapter(object: CompoundButton.OnCheckedChangeListener {
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
Toast.makeText(activity, "checked", Toast.LENGTH_SHORT).show()
}
})
items_list.adapter = adapter
// Set up ViewModel
checklistViewModel = ViewModelProviders.of(this).get(ChecklistViewModel::class.java)
checklistViewModel.allToDoItems.observe(this, Observer { toDoItems ->
toDoItems?.let { adapter.setToDoItems(it) }
})
// Set up fab
add_list_item_fab.setOnClickListener {
checklistViewModel.insert(ToDoItem(description = "Item ${Random.nextInt(1,999)}", checked = Random.nextBoolean()))
}
}
}
这是我当前的适配器:
class ToDoItemAdapter(val onCheckedChangeListener: CompoundButton.OnCheckedChangeListener) : RecyclerView.Adapter<ToDoItemAdapter.ViewHolder>() {
private var toDoItems = emptyList<ToDoItem>()
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val checkbox: CheckBox = view.checkbox
val tvDescription: TextView = view.tv_description
fun bind(position: Int) {
checkbox.isChecked = toDoItems[position].checked
checkbox.setOnCheckedChangeListener(onCheckedChangeListener)
tvDescription.text = toDoItems[position].description
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.checklist_item, parent, false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position)
}
override fun getItemCount() = toDoItems.size
internal fun setToDoItems(toDoItems: List<ToDoItem>) {
this.toDoItems = toDoItems
notifyDataSetChanged()
}
}
侦听已检查项目并立即使用MVVM体系结构将这些更改立即存储在数据库中的最佳实践方法是什么?
答案 0 :(得分:1)
如果您想在RecyclerView项目中单击或检查某些内容,
有一种优雅的方法。
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/activity_home_drawer" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/profile_image"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/nav_header_desc"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView
android:id="@+id/user_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/profile_image"
android:layout_toLeftOf="@id/profile_image"
android:gravity="center"
android:text="@string/nav_header_subtitle" />
<TextView
android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/user_email"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/profile_image"
android:fontFamily="@font/uifont"
android:gravity="center"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</RelativeLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
以XML格式
class MyAdapter(val viewModel : ViewModel) : RecyclerView.ViewModel<ViewHolder>{
fun onCreateViewModel(..){
val binding = ItemRecyclerViewBinding.inflate(LayoutInflater.from(parent.context), parent,false)
binding.vm = viewModel
}
}
在ViewModel类中,
<data>
<variable name="vm" type="YourViewModel"/
<variable name="yourItem" type="YourItem"/
</data>
<FrameLayout or something
android:onClick = "@{(view) -> vm.onClickItem(view, yourItem)}">
</FrameLayout>
我写了关于如何从recyclerview项目中监听点击或检查事件
如果要如何将这些数据存储到数据库,则可以在ViewModel类中使用自己的例程
编码愉快!