I am working on a very simple implementation of a RecyclerView that displays data stored in a ViewModel. I am still very new to Android development and am trying to learn the fundamentals. In this situation, all the data to be stored in the ViewModel is stored in a simple list, later on I want to use Room to do this but right now I am struggling to get things working. Currently adding an item to the list only adds that item to the private member (_mainList) of the ViewModel, the public member (mainList) is unchanged, and this is the member passed into the adapter constructor call.
ViewModel:
class ListViewModel : ViewModel() {
private val _mainList = mutableListOf<String>()
val mainList = _mainList.toList()
fun addMainListItem(item: String) {
_mainList.add(item)
}
}
Adapter:
class MainAdapter(private var list: List<String>) :
RecyclerView.Adapter<MainAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.list_item_text.text = list[position]
}
override fun getItemCount(): Int {
return list.size
}
}
Fragment that displays the list:
class MainListFragment : Fragment() {
private val viewModel: ListViewModel by activityViewModels()
private var _binding: FragmentMainListBinding? = null
private val binding get() = _binding!!
lateinit var adapter: MainAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMainListBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Add click listener to floating action button
binding.fabMain.setOnClickListener {
addListItem()
}
adapter = MainAdapter(viewModel.mainList)
main_list_view.adapter = adapter
main_list_view.layoutManager = LinearLayoutManager(requireContext())
}
private fun addListItem() {
val input = EditText(activity)
input.setHint("Enter the name of your new list item")
input.inputType = InputType.TYPE_CLASS_TEXT
activity?.let {
val builder = AlertDialog.Builder(activity)
builder.apply {
setTitle("Add List Item")
setView(input)
setPositiveButton(
"Add"
) { dialog, id ->
val newItem = input.text.toString()
viewModel.addMainListItem(newItem)
adapter.notifyDataSetChanged()
}
setNegativeButton("Cancel"
) { dialog, id ->
dialog.cancel()
}
}
builder.create()
builder.show()
}
}
}
add Method in the adapter also make list to ArrayList and public visibility
Or if you want to observe changes from ViewModel then add the observing event in your fragment. ViewModel list observing events is best practice in your case.