1

I'm using architecture-components-samples to learn how multiple back stacks work. Initially, the example works well. I'm interested in the Leaderboard tab, which contains a list of users. In this example, I added Koin and created a LeaderboardViewModel for long-term state storage.

LeaderboardViewModel

class LeaderboardViewModel : ViewModel() {
    private val _users = MutableSharedFlow<Array<String>>(1)
    val users: SharedFlow<Array<String>> = _users

   init {
        Log.d("test_t", "Init VM")
        initUserList()
    }

    private fun initUserList() {
        viewModelScope.launch(Dispatchers.IO) {
            _users.emit(Array(100) { "Person ${it + 1}" })
        }
    }

    override fun onCleared() {
        super.onCleared()
        Log.d("test_t", "LeaderboardViewModel onCleared")
    }
}

LeaderboardFragment

/**
 * Shows a static leaderboard with multiple users.
 */
class Leaderboard : Fragment() {
    private val viewModel: LeaderboardViewModel by koinNavGraphViewModel(R.id.list)
    private lateinit var viewAdapter: MyAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_leaderboard, container, false)

        lifecycleScope.launchWhenCreated {
            viewModel.users.collect {
                viewAdapter = MyAdapter(it)

                view.findViewById<RecyclerView>(R.id.leaderboard_list).run {
                    adapter = viewAdapter
                }
            }
        }

        return view
    }
}

class MyAdapter(private val myDataset: Array<String>) :
    RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    class ViewHolder(val item: View) : RecyclerView.ViewHolder(item)

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        // create a new view
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.list_view_item, parent, false)

        return ViewHolder(itemView)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.item.findViewById<TextView>(R.id.user_name_text).text = myDataset[position]

        holder.item.findViewById<ImageView>(R.id.user_avatar_image)
            .setImageResource(listOfAvatars[position % listOfAvatars.size])

        holder.item.setOnClickListener {
            val bundle = bundleOf(USERNAME_KEY to myDataset[position])

            holder.item.findNavController().navigate(
                R.id.action_leaderboard_to_userProfile,
                bundle
            )
        }
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = myDataset.size

    companion object {
        const val USERNAME_KEY = "userName"
    }
}

private val listOfAvatars = listOf(
    R.drawable.avatar_1_raster,
    R.drawable.avatar_2_raster,
    R.drawable.avatar_3_raster,
    R.drawable.avatar_4_raster,
    R.drawable.avatar_5_raster,
    R.drawable.avatar_6_raster
)

Navigation.xml

<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@+id/home">

    <include app:graph="@navigation/home"/>
    <include app:graph="@navigation/list"/>
    <include app:graph="@navigation/form"/>

</navigation>

At first glance, this works well when switching tabs.

enter image description here

But when I am on this tab and click on the BackButton, then my ViewModel is destroyed (call onCleared), and as a result of which the whole state returns to its original state.

enter image description here

Please tell me how can I fix this? I need that when I click on the BackButton and the next switching to other tabs, the ViewModel is not destroyed. What are some ideas? Thanks

Tomas
  • 1,567
  • 3
  • 21
  • 38

0 Answers0