Reputation: 405
I am creating Recyclerview using MVVM and data binding. Now I need to perform some network operation in Recycler view adapter. So how can we create ViewModel and Live data for adapter. How can adapter observe live data.
I have create ViewModel using activity context and but not working proper
class CartAdapter(cartList: ArrayList<ProductData>, context: BaseActivity) :
RecyclerView.Adapter<CartAdapter.MyViewHolder>() {
private val itemList = cartList
private val activity = context
private var viewModel: CartAdapterViewModel =
ViewModelProvider(context).get(CartAdapterViewModel::class.java)
init {
initObserver()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.cart_item_layout, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = itemList[position]
holder.setData(item)
}
override fun getItemCount(): Int {
return itemList.size
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var binding: CartItemLayoutBinding? = DataBindingUtil.bind(itemView)
fun setData(model: ProductData) {
binding?.item = model
}
}
private fun initObserver() {
viewModel.statusResponse.observe(activity, {
activity.hideLoader()
})
viewModel.serverError.observe(activity, {
activity.hideLoader()
})
}
}
Upvotes: 0
Views: 5329
Reputation: 1970
You should not create a separate ViewModel
for adapter.
The Classic way:
The adapter should expose an interface whose implementation would later handle e.g. clicks on an item in the RecyclerView
.
class CartAdapter(
cartList: ArrayList<ProductData>,
private val itemClickListener: ItemClickListener // This is the interface implementation
// that will be provided for an item click in this example
) : RecyclerView.Adapter<CartAdapter.MyViewHolder>() {
interface ItemClickListener {
fun onItemClick(position: Int)
}
override fun onBindViewHolder(holder: ScanResultViewHolder, position: Int) {
holder.binding.root.setOnClickListener {
itemClickListener.onItemClick(position)
}
}
// this function would be useful for retrieving an item from the recyclerview
fun getItemAt(position: Int): ProductData = itemList[position]
...
}
Later on when instantiating the CartAdapter
in Your Activity
or Fragment
You would have to provide that interface implementation:
private val cartAdapter: CartAdapter = CartAdapter(
cartList,
object : CartAdapter.ItemClickListener {
override fun onItemClick(position: Int) {
// this function will handle the item click on a provided position
doSomethingWithARecyclerViewItemFrom(position)
}
}
)
private fun doSomethingWithARecyclerViewItemFrom(position: Int) {
// get the adapter item from the position
val item = cartAdapter.getItemAt(position)
// later on You can use that item to make something usefull with Your ViewModel of an activity/fragment
...
}
This way the Adapter
doesn't have to have any ViewModel
s - the corresponding actions on RecyclerView
items can be handled by the Activity
view model.
In my example this action is an item click but for a more specific action, You would have to update Your question with those details.
The more compact way:
You can implement the same functionality as above using even more compact and neat way by using function types
:
class CartAdapter(
cartList: ArrayList<ProductData>,
private val itemClickListener: (productData: ProductData) -> Unit // notice here
) : RecyclerView.Adapter<CartAdapter.MyViewHolder>() {
override fun onBindViewHolder(holder: ScanResultViewHolder, position: Int) {
holder.binding.root.setOnClickListener {
itemClickListener(position) // slight change here also
}
}
}
Upvotes: 2
Reputation: 91
My suggestion is using constructor to pass viewModel instance. Without concerns of unhandled instance scope problem anyway.
Have a happy day.
Upvotes: 0