Premise

An Android school project which uses different APIs to get a list of all Pokémons and information about them. This specific piece of code relates to a list of all pokémons, or a Pokédex.

Specifically, a RecyclerAdapter which sets the OnClickListener for each row to the same thing:

class PokedexRecyclerAdapter(val context: Context,
                             val data: MutableList<PokedexEntry>):
       RecyclerView.Adapter<PokedexRecyclerAdapter.ViewHolder>() {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        
        val rowView : View = LayoutInflater.from(context)
                             .inflate(R.layout.pokedex_list_item, parent, false)

        rowView.setOnClickListener{
            (context as MainActivity).onEntryListClicked(it.tag.toString())
        }
        
        return ViewHolder(rowView)

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // [...]
    }
}

Problem

As each row of the RecyclerView is a different pokémon, in some specific fragments I needed to change the callback to a specific method call for each entry.

The method I needed to call looked as follows:

    private fun setUpSelectedPokemon(data: PokedexEntry) {

        selectedPokemon = data

        // Clear second type if new pokémon only has one
        resetSelectedPokemon(data)

        selectedPokemonNameTextView.text = data.name

        // [...] More code that configures the selected Pokémon layout elements
    }

Solution

The first step to fix this is to pass the callback as an argument to the RecyclerAdapter although the main fix comes from moving the assignment of the callback from onCreateViewHolder() to onBindViewHolder() which has access to the ViewHolder and the position of the element in the list.

So the RecyclerAdapter now looks like this:

class PokedexRecyclerAdapter(val context: Context,
                             val data: MutableList<PokedexEntry>,
                             val callback: ((PokedexEntry) -> Unit)? = null):
       RecyclerView.Adapter<PokedexRecyclerAdapter.ViewHolder>() {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        
        val rowView : View = LayoutInflater.from(context)
                             .inflate(R.layout.pokedex_list_item, parent, false)
        
        return ViewHolder(rowView)

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        
        // [...]

        if (callback != null) {
            holder.itemView.setOnClickListener{
                callback!!(data[position])
            }
        } else {
            holder.itemView.setOnClickListener{
                (context as MainActivity).onEntryListClicked(it.tag.toString())
            }
        }

    }
}

Which can then be called like this from our Fragment:

pokemonListRecyclerView.adapter = 
PokedexRecyclerAdapter(activity as MainActivity, data)
                          { elt -> setUpSelectedPokemon(elt) }