Android: Rate limit refreshInputOverlay calls from sliders

Sliders can trigger change listeners very rapidly, so let's add some
rate limiting so dragging a slider doesn't cause the whole UI to lag.
(Now the input overlay looks laggy when dragging a slider, though.)
This commit is contained in:
JosJuice 2025-11-09 14:25:42 +01:00
parent a026a0d5e4
commit 060f792560
2 changed files with 41 additions and 2 deletions

View File

@ -8,6 +8,8 @@ import android.graphics.Rect
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.SparseIntArray import android.util.SparseIntArray
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MenuItem import android.view.MenuItem
@ -61,6 +63,7 @@ import org.dolphinemu.dolphinemu.ui.main.ThemeProvider
import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization import org.dolphinemu.dolphinemu.utils.DirectoryInitialization
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper import org.dolphinemu.dolphinemu.utils.FileBrowserHelper
import org.dolphinemu.dolphinemu.utils.RateLimiter
import org.dolphinemu.dolphinemu.utils.ThemeHelper import org.dolphinemu.dolphinemu.utils.ThemeHelper
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -88,6 +91,10 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
private lateinit var binding: ActivityEmulationBinding private lateinit var binding: ActivityEmulationBinding
private val refreshInputOverlayRateLimiter = RateLimiter(Handler(Looper.getMainLooper()), 100) {
emulationFragment?.refreshInputOverlay()
}
private val requestChangeDisc = registerForActivityResult( private val requestChangeDisc = registerForActivityResult(
ActivityResultContracts.GetContent() ActivityResultContracts.GetContent()
) { uri: Uri? -> ) { uri: Uri? ->
@ -729,7 +736,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
addOnChangeListener { _: Slider?, value: Float, _: Boolean -> addOnChangeListener { _: Slider?, value: Float, _: Boolean ->
dialogBinding.inputScaleValue.text = "${(value.toInt() + 50)}%" dialogBinding.inputScaleValue.text = "${(value.toInt() + 50)}%"
IntSetting.MAIN_CONTROL_SCALE.setInt(settings, value.toInt()) IntSetting.MAIN_CONTROL_SCALE.setInt(settings, value.toInt())
emulationFragment?.refreshInputOverlay() refreshInputOverlayRateLimiter.run()
} }
} }
inputScaleValue.text = inputScaleValue.text =
@ -742,7 +749,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
addOnChangeListener { _: Slider?, value: Float, _: Boolean -> addOnChangeListener { _: Slider?, value: Float, _: Boolean ->
inputOpacityValue.text = value.toInt().toString() + "%" inputOpacityValue.text = value.toInt().toString() + "%"
IntSetting.MAIN_CONTROL_OPACITY.setInt(settings, value.toInt()) IntSetting.MAIN_CONTROL_OPACITY.setInt(settings, value.toInt())
emulationFragment?.refreshInputOverlay() refreshInputOverlayRateLimiter.run()
} }
} }
inputOpacityValue.text = inputOpacitySlider.value.toInt().toString() + "%" inputOpacityValue.text = inputOpacitySlider.value.toInt().toString() + "%"

View File

@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.utils
import android.os.Handler
import android.os.SystemClock
class RateLimiter(
private val handler: Handler,
private val delayBetweenRunsMs: Int,
private val runnable: Runnable
) {
private var nextAllowedRun = 0L
private var pendingRun = false
fun run() {
if (!pendingRun) {
val time = SystemClock.uptimeMillis()
if (time >= nextAllowedRun) {
runnable.run()
nextAllowedRun = time + delayBetweenRunsMs
} else {
pendingRun = true
handler.postAtTime({
runnable.run()
nextAllowedRun = SystemClock.uptimeMillis() + delayBetweenRunsMs
pendingRun = false
}, nextAllowedRun)
}
}
}
}