Search code examples
androidandroid-fragmentsandroid-recyclerviewfragment-lifecycle

At what point in the Fragment lifecycle is a RecyclerView ready?


I populate the RecyclerView like this:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(R.layout.player, container, false)
    view.findViewById<RecyclerView>(R.id.songs).adapter = object: RecyclerView.Adapter<MyViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val item = LayoutInflater.from(parent.context).inflate(R.layout.item_song, parent, false)
            return MyViewHolder(item)
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            (holder.item as TextView).text = files[position].tag.title()
        }

        override fun getItemCount(): Int = files.size
    }
    return view
}

item_song.xml is just a TextView.

Now I want to make the currently playing song Bold:

        val songs = view?.findViewById<RecyclerView>(R.id.songs)
        
        val song = songs?.findViewHolderForAdapterPosition(0)?.itemView as TextView
        // or val song = songs?.layoutManager?.findViewByPosition(0) as TextView
        song.setTypeface(song.typeface, Typeface.BOLD)

When I throw this code into the OnClickListener for some Button, it works. The item gets bold. However, I want this to happen before the view is presented to the user. But when I put this code in onStart, onResume, or even in onViewCreated, both

songs?.findViewHolderForAdapterPosition(0)

and

songs?.layoutManager?.findViewByPosition(0)

return null. Always. Thus it seems to me that the RecyclerView has not been populated yet with the items from files. So the question is, when exactly in the Fragment lifecycle does that happen? At what point is it safe to call above methods?


Solution

  • Now I want to make the currently playing song Bold:

    Step #1: Have the model data reflect whether or not the song is current. In other words, whatever files is should hold this data.

    Step #2: Have your onBindViewHolder() take this into account when updating the views of the row. For every onBindViewHolder() call, update the TextView to be normal or bold based on the model data.

    Step #3: When the currently-playing song changes, update the model data to reflect the changes, and call notifyItemChanged() on the RecyclerView.Adapter to tell the adapter that the two positions (formerly-current and newly-current) need to be re-rendered.

    Now I want to make the currently playing song Bold:

    That is not a good solution. Beyond the problems that you are currently seeing, it will not work with scrolling:

    • Rows get recycled, and so now some random other song is bold as the user scrolls your list

    • The same row does not get reused for the same position, so when your user scrolls back, your currently-playing song might not be bold anymore

    So the question is, when exactly in the Fragment lifecycle does that happen?

    There is no relationship between the fragment lifecycle and when the RecyclerView sets up its views.