I have recyclerView and after click of card I would like to replace fragments in activity. The problem is I have no access to activity. Here is my code in adapter:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itemsViewModel = mList[position]
holder.tagImage.setImageResource(itemsViewModel.tagImage)
holder.tagName.text = itemsViewModel.tagName
holder.tagDescription.text = itemsViewModel.tagDescription
holder.itemView.setOnClickListener {
Log.d(InTorry.TAG, itemsViewModel.tagName)
val fragment = ProductsFragment()
val transaction = activity?.supportFragmentManager?.beginTransaction()
transaction?.replace(R.id.homeFragmentsContainer, fragment)
//transaction?.disallowAddToBackStack()
transaction?.commit()
}
}
The above replace code works in fragment but in adapter there is "activity?" error.
Kind Regards
Jack
CodePudding user response:
There are multiple ways to solve this problem.
- Using Context
You can use the context from holder.itemView
and cast it into an Activity
.
This is probably the simplest way, however this can be problematic since a Context
may represent an Activity
, a Service
, an Application
, etc. in which case it may lead to a ClassCastException
when used simply.
- Using Callback
You can set up a callback from your Adapter to your Activity
or Fragment
and then replace your Fragment
.
- Use JetPack Navigation
This is my personal favorite as the latest versions allow you to access NavController
from Activity
, Fragment
or any View
in the hierarchy to navigate. This is just one of many benefits of using this library.
Here is a link to Jetpack Navigation.
CodePudding user response:
To fix the error pass a reference of the activity to the adapter's constructor and save it as a member variable. Then use that variable to access the activity and perform the fragment transaction.
class MyAdapter(
private val activity: Activity,
private val mList: List<ItemsViewModel>
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Your existing code here
holder.itemView.setOnClickListener {
// Use the activity variable to access the activity and perform the fragment transaction
val fragment = ProductsFragment()
val transaction = activity.supportFragmentManager.beginTransaction()
transaction.replace(R.id.homeFragmentsContainer, fragment)
transaction.commit()
}
}
// Other adapter methods here
}
When instantiating adapter, pass a reference to the activity to its constructor:
val adapter = MyAdapter(this, mList)
Alternatively, instead of passing the activity to the adapter, it is possible to pass a FragmentManager
to the adapter, which can be used to perform the fragment transaction.
class MyAdapter(
private val fragmentManager: FragmentManager,
private val mList: List<ItemsViewModel>
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Your existing code here
holder.itemView.setOnClickListener {
// Use the fragmentManager variable to perform the fragment transaction
val fragment = ProductsFragment()
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.homeFragmentsContainer, fragment)
transaction.commit()
}
}
// Other adapter methods here
}
Pass a reference to the FragmentManager
to adapter constructor. This way lets avoid passing an activity reference to the adapter, which makes code more modular and reusable.
val adapter = MyAdapter(supportFragmentManager, mList)