Kotlin: How to call getSupportFragmentManager() in RecyclerView.Adapter

Viewed 14415

I would like to call the Support Fragment Manager in my RecyclerView.Adapter after the click event in order to move to a different fragment. My approach:

(context as MainActivity).supportFragmentManager
                            .beginTransaction()
                            .replace(MainActivity.FRAGMENT_CONTAINER, TextScreen())
                            .commit()

But I get the following error:

kotlin.TypeCastException: null cannot be cast to non-null type

Can you help me?

4 Answers

Updated for 2021 - Kotlin Answer

If you want to call "supportFragmentManager" in Fragment

activity.supportFragmentManager

This is because your Context instance in the adapter is not guaranteed to be an Activity. It could potentially be a ContextWrapper holding the Activity as a base Context. Attempting to unwrap this would be fragile.

Instead, I would recommend that you define an interface in your adapter. From your Activity, provide an implementation of this interface to your adapter that will perform the FragmentTransaction. For example:

class MyAdapter : RecyclerView.Adapter<MyType> {
    private var listener: (() -> Unit)? = null

    fun setListener(listener: (() -> Unit)?) {
        this.listener = listener
    }

    // wherever your onClick is handled:
    listener?.invoke()
}

Then, in the Activity that's initializing MyAdapter:

myAdapter.setListener {
    supportFragmentManager
        .beginTransaction()
        .replace(MainActivity.FRAGMENT_CONTAINER, TextScreen())
        .commit()
}

I suggest you handle your fragment transaction in your fragment/activity. This would help you to have cleaner code and using context in fragment/activity is much easier. Try to define the interface between your adapter and fragment and call your interface method in the adapter and implement the interface in activity/fragment. There you can access context easily.

get the activity or fragment as argument in your adapter.

class ArticleAdapter(private val articleActivity: ArticleActivity, private val docs: List<ArticleResult.ArticleDoc>) : RecyclerView.Adapter<ArticleAdapter.Holder>() {
    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): Holder = Holder(LayoutInflater.from(p0.context).inflate(R.layout.row_general2, p0, false))
    override fun getItemCount(): Int = docs.size

    override fun onBindViewHolder(holder: Holder, position: Int) {
        articleActivity.supportFragmentManager
    }

    class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textViewTitleRow = itemView.findViewById<TextView>(R.id.textViewTitleRow)!!
        val textView1Row = itemView.findViewById<TextView>(R.id.textView1Row)!!
        val textView2Row = itemView.findViewById<TextView>(R.id.textView2Row)!!
        val imageViewDownloadRow = itemView.findViewById<ImageView>(R.id.imageViewDownloadRow)!!
        val textViewMoreRow = itemView.findViewById<TextView>(R.id.textViewMoreRow)!!
        val imageViewBookRow = itemView.findViewById<ImageView>(R.id.imageViewBookRow)!!
    }
}
Related