Home > Software engineering >  Kotlin access activity on recyclerView Adapter
Kotlin access activity on recyclerView Adapter

Time:12-04

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.

  1. 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.

  1. Using Callback

You can set up a callback from your Adapter to your Activity or Fragment and then replace your Fragment.

  1. 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)
  • Related