Search code examples
androidkotlinfragmentandroid-gridlayout

Retaining Int after view gets destroyed


I am using a gridlayout in a fragment on which the user can switch the amount of items shown per line (by pressing a button he can switch currently between 6 and 4 but might extend on adding a third option).

When the user leaves the the fragment (switches to another fragment) and comes back later, I want to retain the information of how many items per line are shown.

After having tried different options (savedInstanceState: doesn't work as the activity is never recreated, getArguments: not a feasible option afaik, as I have to pass the information several times) I am using a sharedViewModel that is implemented anyways as some of information is observed.

I feel like it's an overkill, as it is "just" an int (or even a bool, if there are just 2 states) and there might be a more simple ("built in"?) solution which might be similiar to activity's savedInstanceState.

Here is some code:

Fragment with GridLayout

class LibraryFragment : Fragment() {

    private val model: SharedViewModel by activityViewModels()
    private lateinit var gridlayoutManager: GridLayoutManager
    private lateinit var thumbnailAdapter: ThumbnailAdapter
    private lateinit var thumbnailRecyclerView: RecyclerView
    private var booksPerLine = 4

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentLibraryViewerBinding.inflate(layoutInflater)
        val view = libraryFragmentBinding.root
        initRecyclerView()
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.booksPerLine.observe(viewLifecycleOwner, Observer {
            booksPerLine = it
            switchNoOfBooksPerLine()
        })
    }

    private fun initRecyclerView() {
        thumbnailRecyclerView = libraryFragmentBinding.thumbnailRecyclerView
        switchNoOfBooksPerLine()
        thumbnailAdapter = ThumbnailAdapter { selectedBook: Book -> displaySelectedBook(selectedBook) }
        thumbnailAdapter.setThumbnailList(listOf())
        thumbnailRecyclerView.adapter = thumbnailAdapter
    }

    private fun switchNoOfBooksPerLine() {
        gridlayoutManager = GridLayoutManager(requireContext(), booksPerLine, LinearLayoutManager.VERTICAL, false)
        thumbnailRecyclerView.layoutManager = gridlayoutManager
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.change_grid -> {
                when (booksPerLine) {
                    4 -> model.setBooksPerLine(6)
                    6 -> model.setBooksPerLine(4)
                }
                true
            }
        }
    }

}

SharedViewModel with grid information

class SharedViewModel : ViewModel() {
    val booksPerLine = MutableLiveData<Int>()

    internal fun setBooksPerLine(_booksPerLine: Int) {
        booksPerLine.value = _booksPerLine
    }
}
  • So the questions is, if there is a more simple/efficient way of retaining the Int? (bonus question: how efficient (in terms of ressource usage like memory) is a SharedViewModel actually?

  • Is there a built in method like savedInstanceState for activities for fragments, too?


Solution

  • I would suggest to keep the data in the activity. And in fragment get the data from activity in onViewCreated method like-

    val data = (activity as MyActivity)?.data
    

    Also, put back the data into the activity the other way when data changed-

    (activity as MyActivity)?.data = changedData
    

    This is the manual way. Keep in mind the data is nullable.