Reputation: 4164
I'm still trying to wrap my head around working with viewmodels and a bit confused now that I also have a dialog and recyclerview items but will try to be as clear as I can here if I can get any help please.
I have a dialog with items that when one of them is selected and closed should return data to my calling fragment so the selected item is displayed under that view.
However, once the item is selected and the dialog dismissed, I don't see the new selected item as the one showing on the UI but still the old item instead. (When the fragment is first started it displays the item that is set as selected on my list. The selected value is hardcoded at first but updated when the item is clicked and I can see the update has taken place when I debug the viewmodel observer inside the onDismiss method for the dialog).
I'm a couple of hours on this and have tried a few different things such as calling the viewmodel inside onResume or onDismiss and changing the viewmodel to be initiated by by activityViewModels()
as per this post but none of these have worked so far and I think I'm stuck at the moment. Below my most recent version of the code.
class CovidCheckInFragment : Fragment(R.layout.fragment_covid_check_in) {
var navController: NavController? = null
private val model: MainViewModel by activityViewModels()
@RequiresApi(Build.VERSION_CODES.M)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
model.userMutableLiveData.observe(viewLifecycleOwner, Observer<Any?> { list ->
if (list != null)
(list as Iterable<*>).map {
if ((it as ModelDialogOption).selected == true) {
tvHeader.text = it.title
}
}
})
}
}
..
class MyDialogFragment : DialogFragment(), RecyclerDialogOptionsItem.AdapterListener {
private val viewModel: MainViewModel by activityViewModels()
private lateinit var adapter: GroupAdapter<GroupieViewHolder>
var selectedPosition = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.AppTheme_Dialog_Custom)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rvOptions.layoutManager = LinearLayoutManager(activity)
adapter = GroupAdapter()
rvOptions.adapter = adapter
ivClose.setOnClickListener {
this.dismiss()
}
initViewModel()
}
private fun initViewModel() {
viewModel.userMutableLiveData.observe(this, Observer { list ->
for (i in list!!) {
adapter.add(
RecyclerDialogOptionsItem(
this@MyDialogFragment,
i,
this@MyDialogFragment
)
)
}
})
}
override fun onClickItem(position: Int) {
selectedPosition = position
adapter.notifyDataSetChanged()
Log.i("clicked", "position: $position")
}
}
..
class MainViewModel : ViewModel() {
private var list: ArrayList<ModelDialogOption>? = null
val userMutableLiveData: MutableLiveData<ArrayList<ModelDialogOption>?> = MutableLiveData()
init {
populateList()
userMutableLiveData.value = list!!
}
private fun populateList() {
list = ArrayList()
list!!.add(ModelDialogOption("Prefer not to say", false))
list!!.add(ModelDialogOption("16-39", false))
list!!.add(ModelDialogOption("40-59", true))
list!!.add(ModelDialogOption("60+", false))
}
}
..
class RecyclerDialogOptionsItem(
private val fragment: MyDialogFragment,
private val modelDialogOption: ModelDialogOption,
private val adapterListener: AdapterListener
) : Item<GroupieViewHolder>() {
companion object {
var clickListener: AdapterListener? = null
}
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.apply {
with(viewHolder.itemView) {
tvTitle.text = modelDialogOption.title
clickListener = adapterListener
if (fragment.selectedPosition == position) {
ivChecked.visible()
modelDialogOption.selected = true
} else {
ivChecked.invisible()
modelDialogOption.selected = false
}
itemView.setOnClickListener {
clickListener?.onClickItem(adapterPosition)
}
}
}
}
override fun getLayout() = R.layout.rv_options_item_row
interface AdapterListener {
fun onClickItem(position: Int)
}
}
Thank you very much.
Upvotes: 2
Views: 1491
Reputation: 246
Your main view model should be like this
class MainViewModel : ViewModel() {
private var list: ArrayList<ModelDialogOption>? = null
val userMutableLiveData = MutableLiveData<ArrayList<ModelDialogOption>>()
init {
populateList()
userMutableLiveData.value = list!!
}
private fun populateList() {
list = ArrayList()
list!!.add(ModelDialogOption("Prefer not to say", false))
list!!.add(ModelDialogOption("16-39", false))
list!!.add(ModelDialogOption("40-59", true))
list!!.add(ModelDialogOption("60+", false))
}
fun updateItem(position:Int){
val itemToUpdate = list!!.get(position)
itemToUpdate.selected = !itemToUpdate.selected!!
list!![position] = itemToUpdate
}
fun flushItems(){
userMutableLiveData.value = list!!
}
}
Then from MyDialogFragment Should be like this.
class MyDialogFragment : DialogFragment(), RecyclerDialogOptionsItem.AdapterListener {
private val viewModel: MainViewModel by activityViewModels()
private lateinit var adapter: GroupAdapter<GroupieViewHolder>
var selectedPosition = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.AppTheme_Dialog_Custom)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_dialog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rvOptions.layoutManager = LinearLayoutManager(activity)
adapter = GroupAdapter()
rvOptions.adapter = adapter
ivClose.setOnClickListener {
this.dismiss()
}
initViewModel()
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
viewModel.flushItems()
}
private fun initViewModel() {
viewModel.userMutableLiveData.observe(this, Observer { list ->
for (i in list!!) {
adapter.add(
RecyclerDialogOptionsItem(
this@MyDialogFragment,
i,
this@MyDialogFragment
)
)
}
})
}
override fun onClickItem(position: Int) {
selectedPosition = position
adapter.notifyDataSetChanged()
viewModel.updateItem(position)
Log.i("clicked", "position: $position")
}
}
Upvotes: 1