[Android] Limit buble text updates at 10Hz

Geoffrey Métais git at videolan.org
Thu Feb 14 14:15:53 CET 2019


vlc-android | branch: master | Geoffrey Métais <geoffrey.metais at gmail.com> | Thu Feb 14 14:15:12 2019 +0100| [d528cc5d1e4a0a1f12d8d11798376410ead6fc1f] | committer: Geoffrey Métais

Limit buble text updates at 10Hz

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

 .../src/org/videolan/vlc/gui/view/FastScroller.kt  | 55 ++++++++++------------
 .../videolan/vlc/viewmodels/paged/MLPagedModel.kt  |  2 +-
 .../vlc/viewmodels/paged/PagedAlbumsModel.kt       |  3 +-
 .../vlc/viewmodels/paged/PagedArtistsModel.kt      |  3 +-
 .../vlc/viewmodels/paged/PagedTracksModel.kt       |  3 +-
 5 files changed, 28 insertions(+), 38 deletions(-)

diff --git a/vlc-android/src/org/videolan/vlc/gui/view/FastScroller.kt b/vlc-android/src/org/videolan/vlc/gui/view/FastScroller.kt
index 534f3b4cd..04503f72d 100644
--- a/vlc-android/src/org/videolan/vlc/gui/view/FastScroller.kt
+++ b/vlc-android/src/org/videolan/vlc/gui/view/FastScroller.kt
@@ -44,6 +44,8 @@ import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.appbar.AppBarLayout
 import com.google.android.material.floatingactionbutton.FloatingActionButton
 import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.actor
 import org.videolan.medialibrary.media.MediaLibraryItem
 import org.videolan.vlc.R
 import org.videolan.vlc.util.WeakHandler
@@ -61,12 +63,12 @@ private const val SHOW_SCROLLER = 2
 
 private const val ITEM_THRESHOLD = 25
 
+ at ObsoleteCoroutinesApi
 @ExperimentalCoroutinesApi
 class FastScroller : LinearLayout, CoroutineScope {
     override val coroutineContext = Dispatchers.Main.immediate + SupervisorJob()
     private var currentHeight: Int = 0
     private var itemCount: Int = 0
-    private var recyclerviewTotalHeight: Int = 0
     private var fastScrolling: Boolean = false
     private var showBubble: Boolean = false
     private var currentPosition: Int = 0
@@ -74,6 +76,7 @@ class FastScroller : LinearLayout, CoroutineScope {
     private var currentAnimator: AnimatorSet? = null
     private val scrollListener = ScrollListener()
     private lateinit var recyclerView: RecyclerView
+    private lateinit var layoutManager: LinearLayoutManager
     private lateinit var model: MLPagedModel<out MediaLibraryItem>
     private lateinit var handle: ImageView
     private lateinit var bubble: TextView
@@ -88,9 +91,10 @@ class FastScroller : LinearLayout, CoroutineScope {
     private var lastVerticalOffset: Int = 0
     private var tryCollapseAppbarOnNextScroll = false
     private var tryExpandAppbarOnNextScroll = false
+    private val sb = StringBuilder()
 
 
-    private val handler = object : FastScrollerHandler(this) {
+    private val handler = object : WeakHandler<FastScroller>(this) {
         override fun handleMessage(msg: Message) {
             when (msg.what) {
                 HIDE_HANDLE -> hideBubble()
@@ -155,9 +159,7 @@ class FastScroller : LinearLayout, CoroutineScope {
     override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
         super.onSizeChanged(w, h, oldw, oldh)
         currentHeight = h
-        if (::recyclerView.isInitialized) {
-            updatePositions()
-        }
+        if (::recyclerView.isInitialized) updatePositions()
     }
 
     /**
@@ -224,11 +226,11 @@ class FastScroller : LinearLayout, CoroutineScope {
      */
     fun setRecyclerView(recyclerView: RecyclerView, model: MLPagedModel<out MediaLibraryItem>) {
         this.recyclerView = recyclerView
+        this.layoutManager = recyclerView.layoutManager as LinearLayoutManager
         this.recyclerView.removeOnScrollListener(scrollListener)
         visibility = View.INVISIBLE
         itemCount = recyclerView.adapter!!.itemCount
         this.model = model
-        recyclerviewTotalHeight = 0
         recyclerView.addOnScrollListener(scrollListener)
         showBubble = (recyclerView.adapter as SeparatedAdapter).hasSections()
     }
@@ -335,39 +337,30 @@ class FastScroller : LinearLayout, CoroutineScope {
                     tryExpandAppbarOnNextScroll = false
                 }
             }
-
-
         }
     }
 
-    /**
-     * Updates the position of the bubble and refresh the letter
-     */
-    private fun updatePositions() = launch {
-        val sb = StringBuilder()
-        val verticalScrollOffset = recyclerView.computeVerticalScrollOffset()
-        recyclerviewTotalHeight = recyclerView.computeVerticalScrollRange() - recyclerView.computeVerticalScrollExtent()
-        val proportion = if (recyclerviewTotalHeight == 0) 0f else verticalScrollOffset / recyclerviewTotalHeight.toFloat()
-        setPosition(currentHeight * proportion)
-        if (fastScrolling) {
+    private val actor = actor<Unit>(capacity = Channel.CONFLATED) {
+        for (evt in channel) {
             sb.setLength(0)
-            val position = if (currentPosition != -1)
-                currentPosition
-            else
-                (recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
+            val position = layoutManager.findFirstVisibleItemPosition()
             val sectionforPosition = model.getSectionforPosition(position)
             sb.append(' ')
                     .append(sectionforPosition)
                     .append(' ')
-            if (!sectionforPosition.isEmpty()) {
-                bubble.text = sb.toString()
-            }
-            return at launch
+            if (!sectionforPosition.isEmpty()) bubble.text = sb.toString()
+            delay(100L)
         }
-        if (this at FastScroller.visibility == View.INVISIBLE)
-            handler.sendEmptyMessage(SHOW_SCROLLER)
     }
-
-    private open class FastScrollerHandler internal constructor(owner: FastScroller) : WeakHandler<FastScroller>(owner)
-
+    /**
+     * Updates the position of the bubble and refresh the letter
+     */
+    private fun updatePositions() {
+        val verticalScrollOffset = recyclerView.computeVerticalScrollOffset()
+        val recyclerviewTotalHeight = recyclerView.computeVerticalScrollRange() - recyclerView.computeVerticalScrollExtent()
+        val proportion = if (recyclerviewTotalHeight == 0) 0f else verticalScrollOffset / recyclerviewTotalHeight.toFloat()
+        setPosition(currentHeight * proportion)
+        if (visibility == View.INVISIBLE) handler.sendEmptyMessage(SHOW_SCROLLER)
+        if (fastScrolling) actor.offer(Unit)
+    }
 }
diff --git a/vlc-android/src/org/videolan/vlc/viewmodels/paged/MLPagedModel.kt b/vlc-android/src/org/videolan/vlc/viewmodels/paged/MLPagedModel.kt
index c4af1e8d8..5a0befe27 100644
--- a/vlc-android/src/org/videolan/vlc/viewmodels/paged/MLPagedModel.kt
+++ b/vlc-android/src/org/videolan/vlc/viewmodels/paged/MLPagedModel.kt
@@ -124,7 +124,7 @@ abstract class MLPagedModel<T : MediaLibraryItem>(context: Context) : SortableMo
     }
 
     suspend fun getSectionforPosition(position: Int): String {
-        mutex.withLock { for (pos in 0 until headers.size()) if (position < headers.keyAt(pos)) return headers.valueAt(pos) }
+        mutex.withLock { for (pos in 0 until headers.size()) if (position <= headers.keyAt(pos)) return headers.valueAt(pos) }
         return ""
     }
 
diff --git a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedAlbumsModel.kt b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedAlbumsModel.kt
index 992da7901..b281d1187 100644
--- a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedAlbumsModel.kt
+++ b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedAlbumsModel.kt
@@ -45,8 +45,7 @@ class PagedAlbumsModel(context: Context, val parent: MediaLibraryItem? = null) :
             is Genre -> parent.searchAlbums(filterQuery, sort, desc, loadSize, startposition)
             else -> medialibrary.searchAlbum(filterQuery, sort, desc, loadSize, startposition)
         }
-        list?.let { completeHeaders(it, startposition) }
-        return list
+        return list.also { completeHeaders(it, startposition) }
     }
 
     override fun getTotalCount() = if (filterQuery == null) when(parent) {
diff --git a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedArtistsModel.kt b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedArtistsModel.kt
index e61666e73..ccfba5fad 100644
--- a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedArtistsModel.kt
+++ b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedArtistsModel.kt
@@ -26,8 +26,7 @@ class PagedArtistsModel(context: Context, private var showAll: Boolean = false):
     override fun getPage(loadSize: Int, startposition: Int): Array<Artist> {
         val list = if (filterQuery == null) medialibrary.getPagedArtists(showAll, sort, desc, loadSize, startposition)
         else medialibrary.searchArtist(filterQuery, sort, desc, loadSize, startposition)
-        list?.let { completeHeaders(it, startposition) }
-        return list
+        return list.also { completeHeaders(it, startposition) }
     }
 
     override fun getTotalCount() = if (filterQuery == null) medialibrary.getArtistsCount(showAll)
diff --git a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedTracksModel.kt b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedTracksModel.kt
index 27c25018a..c7da221d1 100644
--- a/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedTracksModel.kt
+++ b/vlc-android/src/org/videolan/vlc/viewmodels/paged/PagedTracksModel.kt
@@ -65,8 +65,7 @@ class PagedTracksModel(context: Context, val parent: MediaLibraryItem? = null):
             is Playlist -> parent.searchTracks(filterQuery, sort, desc, loadSize, startposition)
             else -> medialibrary.searchAudio(filterQuery, sort, desc, loadSize, startposition)
         }
-        list?.let { completeHeaders(it, startposition) }
-        return list
+        return list.also { completeHeaders(it, startposition) }
     }
 
     override fun getTotalCount() = if (filterQuery == null) when (parent) {



More information about the Android mailing list