[Android] Restore the lists position upon activity recreation by using stateRestorationPolicy

Nicolas Pomepuy git at videolan.org
Mon May 9 11:39:03 UTC 2022


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Fri May  6 13:26:39 2022 +0200| [13303be32d9e2f059eb5d433f626c48168976662] | committer: Duncan McNamara

Restore the lists position upon activity recreation by using stateRestorationPolicy

Fixes #2508

> https://code.videolan.org/videolan/vlc-android/commit/13303be32d9e2f059eb5d433f626c48168976662
---

 .../src/org/videolan/vlc/gui/HistoryFragment.kt        |  2 +-
 .../org/videolan/vlc/gui/audio/AudioBrowserFragment.kt |  8 ++++----
 .../videolan/vlc/gui/browser/BaseBrowserFragment.kt    | 18 +++++-------------
 .../org/videolan/vlc/gui/video/VideoGridFragment.kt    |  6 ++++--
 4 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.kt
index 6cd76cbbb..525a4eafa 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.kt
@@ -52,7 +52,7 @@ class HistoryFragment : MediaBrowserFragment<HistoryModel>(), IRefreshable, IHis
 
     private lateinit var cleanMenuItem: MenuItem
     private lateinit var multiSelectHelper: MultiSelectHelper<MediaWrapper>
-    private val historyAdapter: HistoryAdapter = HistoryAdapter(listEventsHandler = this)
+    private val historyAdapter: HistoryAdapter = HistoryAdapter(listEventsHandler = this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
     private lateinit var itemTouchHelper: ItemTouchHelper
     private lateinit var list: RecyclerView
     private lateinit var empty: TextView
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.kt
index f13b3f214..deb5ab993 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.kt
@@ -180,10 +180,10 @@ class AudioBrowserFragment : BaseAudioBrowser<AudioBrowserViewModel>() {
         viewModel = getViewModel()
         currentTab = viewModel.currentTab
 
-        artistsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_ARTIST, this)
-        albumsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_ALBUM, this)
-        songsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this)
-        genresAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_GENRE, this)
+        artistsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_ARTIST, this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
+        albumsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_ALBUM, this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
+        songsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
+        genresAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_GENRE, this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
         adapters = arrayOf(artistsAdapter, albumsAdapter, songsAdapter, genresAdapter)
         setupProvider()
     }
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
index 4d833124c..8916e6bd7 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
@@ -50,7 +50,10 @@ import org.videolan.vlc.BuildConfig
 import org.videolan.vlc.R
 import org.videolan.vlc.databinding.DirectoryBrowserBinding
 import org.videolan.vlc.gui.AudioPlayerContainerActivity
-import org.videolan.vlc.gui.dialogs.*
+import org.videolan.vlc.gui.dialogs.ConfirmDeleteDialog
+import org.videolan.vlc.gui.dialogs.CtxActionReceiver
+import org.videolan.vlc.gui.dialogs.SavePlaylistDialog
+import org.videolan.vlc.gui.dialogs.showContext
 import org.videolan.vlc.gui.helpers.MedialibraryUtils
 import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.UiTools.addToPlaylist
@@ -72,7 +75,6 @@ import java.util.*
 private const val TAG = "VLC/BaseBrowserFragment"
 
 internal const val KEY_MEDIA = "key_media"
-private const val KEY_POSITION = "key_list"
 const val KEY_PICKER_TYPE = "key_picker_type"
 private const val MSG_SHOW_LOADING = 0
 internal const val MSG_HIDE_LOADING = 1
@@ -87,7 +89,6 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
     private lateinit var layoutManager: LinearLayoutManager
     override var mrl: String? = null
     protected var currentMedia: MediaWrapper? = null
-    private var savedPosition = -1
     override var isRootDirectory: Boolean = false
     override val scannedDirectory = false
     override val inCards = false
@@ -109,7 +110,6 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
         if (bundle != null) {
             currentMedia = bundle.getParcelable(KEY_MEDIA)
             mrl = currentMedia?.location ?: bundle.getString(KEY_MRL)
-            savedPosition = bundle.getInt(KEY_POSITION)
         } else if (requireActivity().intent != null) {
             mrl = requireActivity().intent.dataString
             requireActivity().intent = null
@@ -145,7 +145,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
-        if (!this::adapter.isInitialized) adapter = BaseBrowserAdapter(this)
+        if (!this::adapter.isInitialized) adapter = BaseBrowserAdapter(this).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
         layoutManager = LinearLayoutManager(activity)
         binding.networkList.layoutManager = layoutManager
         binding.networkList.adapter = adapter
@@ -225,7 +225,6 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
     override fun onSaveInstanceState(outState: Bundle) {
         outState.putString(KEY_MRL, mrl)
         outState.putParcelable(KEY_MEDIA, currentMedia)
-        outState.putInt(KEY_POSITION, if (::layoutManager.isInitialized) layoutManager.findFirstCompletelyVisibleItemPosition() else 0)
         super.onSaveInstanceState(outState)
     }
 
@@ -271,7 +270,6 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
     }
 
     override fun onRefresh() {
-        savedPosition = layoutManager.findFirstCompletelyVisibleItemPosition()
         viewModel.refresh()
     }
 
@@ -599,12 +597,6 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
         swipeRefreshLayout.isRefreshing = false
         handler.sendEmptyMessage(MSG_HIDE_LOADING)
         updateEmptyView()
-        if (!viewModel.isEmpty()) {
-            if (savedPosition > 0) {
-                layoutManager.scrollToPositionWithOffset(savedPosition, 0)
-                savedPosition = 0
-            }
-        }
         if (!isRootDirectory) {
             updateFab()
             UiTools.updateSortTitles(this)
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.kt
index c0d0be2cc..e198dce9e 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.kt
@@ -37,8 +37,10 @@ import androidx.recyclerview.widget.RecyclerView
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 import com.google.android.material.appbar.AppBarLayout
 import com.google.android.material.floatingactionbutton.FloatingActionButton
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.medialibrary.interfaces.media.Folder
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
@@ -100,7 +102,7 @@ class VideoGridFragment : MediaBrowserFragment<VideosViewModel>(), SwipeRefreshL
         if (!::settings.isInitialized) settings = Settings.getInstance(requireContext())
         if (!::videoListAdapter.isInitialized) {
             val seenMarkVisible = settings.getBoolean("media_seen", true)
-            videoListAdapter = VideoListAdapter(seenMarkVisible)
+            videoListAdapter = VideoListAdapter(seenMarkVisible).apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY }
             dataObserver = videoListAdapter.onAnyChange {
                 updateEmptyView()
                 if (::binding.isInitialized) binding.fastScroller.setRecyclerView(binding.videoGrid, viewModel.provider)



More information about the Android mailing list