Как передать объект из фрагмента в подробное представление активности с помощью ViewModel (MVVM)?

Я использую MVVM в качестве архитектуры, как передать объект из фрагмента (recycler + viewModel) в действие (подробный вид + viewModel)?

Это модель просмотра фрагмента

class BuyViewModel : ViewModel() {
private lateinit var buys: MutableLiveData<List<Buy>>
private var buyRemote = BuyRemote()
private var buyRepository: BuyRepository = BuyRepository.getInstance(buyRemote)

fun getBuys(): LiveData<List<Buy>> {
    if(!::buys.isInitialized) {
        buys = MutableLiveData()
        buys = buyRepository.getBuys()
    }
    return buys
}

}

Адаптер для фрагмента

class BuyAdapter(internal var context: Context,
             private var resource: Int,
             private var buyList: ArrayList<Buy>
) : RecyclerView.Adapter<BuyAdapter.ViewHolder>() {

override fun getItemCount(): Int {
    return buyList.size
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view = LayoutInflater.from(context)
        .inflate(resource, parent, false)
    return ViewHolder(view)
}


override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val buy: Buy = buyList[position]
    val propertyImages: List<String> =
        buy.propertyImage.split(",")


    //Start DetailView Activity
    holder.itemView.setOnClickListener {
        Toast.makeText(context, "clicked", Toast.LENGTH_SHORT).show()
        val intent = Intent(context, BuyDetailActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        context.startActivity(intent)
    }
}

+++++++++++++++code removed for brevity+++++++++++++++++

И вот, наконец, фрагмент

class BuyFragment : Fragment() {
companion object {
    fun newInstance() = BuyFragment()
}

private lateinit var viewModel: BuyViewModel
private val buyList = ArrayList<Buy>()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel = ViewModelProviders.of(this).get(BuyViewModel::class.java)

    viewModel.getBuys().observe(this, Observer<List<Buy>> { buys ->
        buyList.addAll(buys)
        (rvBuy.adapter as BuyAdapter).notifyDataSetChanged()
    })
}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.buy_fragment, container, false)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    rvBuy.layoutManager = LinearLayoutManager(context)
    rvBuy.adapter = BuyAdapter(activity!!.applicationContext,
        R.layout.buy_card, buyList)
}

Как я могу реализовать это, соблюдая передовой опыт. Когда пользователь щелкает элемент в представлении (фрагменте) ресайклера, он передает действию объект «Купить». Должно ли это действие использовать модель представления само по себе? Как? Должно ли действие использовать ту же модель представления, что и представление переработчика фрагментов?


person Dr4ke the b4dass    schedule 28.02.2019    source источник


Ответы (1)


Вы можете использовать модель общего представления, которая привязана к активности между фрагментами. Получите ViewModel в таких фрагментах.

val sharedViewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)

Затем во фрагменте списка onClick class sharedViewModel.onItemClicked(item)

SharedViewModel {
    private val _selectedItem = MutableLiveData<T>()
    val selectedItem: LiveData<T> get() = _selectedItem

    fun onItemClick(item: T) {
        _selectedItem.value = item
    }
}

Затем во фрагменте детали

sharedViewModel.selectedItem.observe {
    detailViewModel.setItem(it)
}

Затем в подробном представлении модели загрузите элемент и отобразите.

ОБНОВЛЕНИЕ

Чтобы получить доступ к модели общего представления из действия, получите модель представления:

val sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)

Затем наблюдайте за selectedItem LiveData, как за фрагментом.

person Ge3ng    schedule 01.03.2019
comment
Спасибо. У меня нет детального фрагмента, а есть активность. Действие содержит вкладку из трех фрагментов, каждый фрагмент отображает список элементов с помощью recyclerView, когда я нажимаю на элемент, он должен передавать данные (объект) в подробное представление (действие). - person Dr4ke the b4dass; 02.03.2019
comment
метод прослушивателя кликов находится в классе адаптера RecyclerView, а не во фрагменте. - person Dr4ke the b4dass; 06.03.2019
comment
Передайте viewModel адаптеру. - person Ge3ng; 06.03.2019
comment
лучше ли это делать? Я имею в виду, не нарушает ли это принцип MVVM? Я новичок в MVVM. Спасибо за помощь - person Dr4ke the b4dass; 06.03.2019
comment
Нет, MVVM не говорит, что вы говорите свысока (то есть вызываете методы) и реагируете (наблюдаете). И адаптер, и фрагмент / действие являются частью представления. - person Ge3ng; 07.03.2019
comment
@ Ge3ng Не могли бы вы показать демонстрацию того, как мы можем передавать данные из фрагмента в действие (подробное действие, которое будет отображаться после щелчка по элементу списка) с использованием модели представления - person Mohammad Alfaz; 26.09.2020