Android Save and Restore FirestoreUI FirestoreRecyclerAdapter State/Position

May 5, 2020

Fragment

class HomeFragment : Fragment() {
    private val viewModel: HomeViewModel by viewModels()

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        initList()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        viewModel.listState = list.layoutManager?.onSaveInstanceState()
    }

    private fun initList() {
        val query = ...
        val options: FirestoreRecyclerOptions<Post> = FirestoreRecyclerOptions.Builder<Post>()
            .setQuery(query, SnapshotParser { doc ->
                // replace with your own implementation
                Post.toObject(doc)
            })
            .setLifecycleOwner(this)
            .build()

        adapter = LocalAdapter(options, viewModel)

        // this doesn't work as onItemRangeInserted is called multiple times (one by one)
        /*
        adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
            override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                if (viewModel.listState != null) {
                    list.layoutManager?.onRestoreInstanceState(viewModel.listState)
                    viewModel.listState = null
                }
            }
        })
         */

        // use this instead
        adapter.snapshots.addChangeEventListener(object : ChangeEventListener {
            override fun onDataChanged() {
                Timber.d(" Data Changed")
                if (viewModel.listState != null) {
                    list.layoutManager?.onRestoreInstanceState(viewModel.listState)
                    viewModel.listState = null
                }
            }

            override fun onChildChanged(
                type: ChangeEventType,
                snapshot: DocumentSnapshot,
                newIndex: Int,
                oldIndex: Int
            ) {

            }

            override fun onError(e: FirebaseFirestoreException) {

            }
        })

        list.adapter = adapter
    }
}

NOTE: I am using Jetpack Navigation, so I listen to onDestroyView to save state (when navigate to another fragment).

ViewModel

class HomeViewModel : ViewModel() {
    var listState: Parcelable? = null
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.