ViewModel по-прежнему отображает старые данные после закрытия диалога и возврата родительского фрагмента к просмотру

#android #android-fragments #viewmodel #android-dialogfragment #android-viewmodel

#Android #android-фрагменты #viewmodel #android-dialogfragment #android-viewmodel

Вопрос:

Я все еще пытаюсь разобраться в работе с viewmodels и немного смущен теперь, когда у меня также есть элементы диалога и recyclerview, но постараюсь быть максимально понятным, если смогу получить любую помощь, пожалуйста.

У меня есть диалоговое окно с элементами, которые, когда один из них выбран и закрыт, должны возвращать данные в мой вызывающий фрагмент, чтобы выбранный элемент отображался в этом представлении.

Однако, как только элемент выбран и диалоговое окно закрыто, я не вижу новый выбранный элемент как тот, который отображается в пользовательском интерфейсе, но вместо этого остается старый элемент. (При первом запуске фрагмента отображается элемент, который установлен как выбранный в моем списке. Выбранное значение сначала жестко закодировано, но обновляется при нажатии на элемент, и я вижу, что обновление произошло при отладке наблюдателя viewmodel внутри метода onDismiss для диалога).

Я работаю над этим пару часов и попробовал несколько разных вещей, таких как вызов viewmodel внутри onResume или onDismiss и изменение viewmodel для инициализации by by activityViewModels() в соответствии с этим сообщением, но пока ничего из этого не сработало, и я думаю, что я застрял на данный момент. Ниже приведена моя самая последняя версия кода.

 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)
}

}
  

Большое вам спасибо.

Комментарии:

1. Где ваш код активности? В вашей деятельности сначала объявите ViewModel. Тогда CovidCheckInFragment и MyDialogFragment получат ссылку на ViewModel, поскольку вы используете activityViewModels(). Это означает, что CovidCheckInFragment и MyDialogFragment будут использовать одну и ту же виртуальную машину для совместного использования и прослушивания данных

2. Привет! Извините, не знал, что нужно включить код и в действие? Есть ли какой-либо способ избежать этого? Я думаю, что я уже достаточно запутался, управляя этими четырьмя классами..

3. Я обновил сообщение некоторой упрощенной версией для своей деятельности. Спасибо.

4. Я думаю, что теперь я смог заставить его работать, заменив activityViewModels на this private val viewModel: MainViewModel by viewModels( { requireParentFragment() } ) как для родительского фрагмента, так и для диалогового.

5. Теперь просто нужно выяснить, как просмотреть это обновление, как только диалоговое окно будет закрыто, потому что на данный момент мне требуется оставить фрагмент и вернуться к нему, чтобы произошли изменения.

Ответ №1:

Ваша основная модель представления должна быть такой

 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!!
}
  

}

Тогда из MyDialogFragment должно быть так.

 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")
}
  

}