如何使用MVVM在RecyclerView中监听onCheckedChangeListener?

时间:2019-02-26 19:00:17

标签: android mvvm viewmodel

我正在尝试用Kotlin编写一个基本的Todo列表,但想使用推荐的最佳实践和Android体系结构组件。至此,我已经建立了基本的体系结构,并在数据库中存储了一个RecyclerView项目列表,左侧带有一个复选框,右侧是一个描述。到目前为止,当添加新数据时(通过浮动操作按钮),列表会自动更新。现在,我想每当单击特定项目的复选框时立即更新记录。

我无法弄清楚如何或在何处设置复选框侦听器,以将检查状态和项目ID传递给ViewModel以便更新数据库中的数据。我考虑过直接在适配器内部定义侦听器,但是后来找不到任何方法来调用ViewModel的update方法。但是,如果我在片段中设置了侦听器并将其传递给适配器,则找不到找到该项目ID的方法。

todo list screenshot

这是我当前的片段:

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体系结构将这些更改立即存储在数据库中的最佳实践方法是什么?

1 个答案:

答案 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类中使用自己的例程

编码愉快!