B4J Question Debounce

xulihang

Well-Known Member
Licensed User
Longtime User
I need to update the display percentage of an image view, which has PDF rendered into images.

When I am zooming in, it displays the thumbnail and then renders the PDF into a high-fidelity one, which costs time. How to avoid the unnecessary rendering when zooming? I think it is called debounce.

Here is the simulated demo code:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Spinner1 As Spinner
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    Dim jo As JavaObject = Spinner1
    Dim e As Object = jo.CreateEventFromUI("javafx.event.EventHandler", "scroll", Null)
    jo.RunMethod("setOnScroll", Array(e))
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub

Private Sub Spinner1_ValueChanged (Value As Object)
    HeavyJob
End Sub

Private Sub HeavyJob
    Log("HeavyJob")
    Sleep(5000)
    Log("HeavyJob done")
End Sub

Sub Scroll_Event (MethodName As String, Args() As Object) As Object
    Dim scrollevent As JavaObject = Args(0)
    Dim DeltaY As Int=scrollevent.RunMethod("getDeltaY", Null)
    If DeltaY>0 Then
        Spinner1.Value=Spinner1.Value+5
    Else
        Spinner1.Value=Spinner1.Value-5
    End If
    Return Null
End Sub
 

zed

Well-Known Member
Licensed User
The idea is to prevent HeavyJob from being restarted with every tiny zoom variation, and to only run it once the user has finished zooming.

The goal is to prevent Spinner1_ValueChanged from triggering HeavyJob with every value change, and to only launch the high-resolution rendering after a delay without any new events.

The solution would be to use a Timer as a "debounce".
Each time the value changes, a Timer is restarted. If no new changes occur for X milliseconds, the Timer triggers HeavyJob.

If the user continues to zoom, the Timer is reset, and HeavyJob is never launched unnecessarily.

Add Private DebounceTimer As Timer to Process_Globals

Example:
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show

    DebounceTimer.Initialize("DebounceTimer", 300) ' 300ms delay
    DebounceTimer.Enabled = False

    Dim jo As JavaObject = Spinner1
    Dim e As Object = jo.CreateEventFromUI("javafx.event.EventHandler", "scroll", Null)
    jo.RunMethod("setOnScroll", Array(e))
End Sub

Private Sub Spinner1_ValueChanged (Value As Object)
    DebounceTimer.Enabled = False '
    DebounceTimer.Enabled = True ' restarts the timer
End Sub

Sub DebounceTimer_Tick
    DebounceTimer.Enabled = False
    HeavyJob
End Sub

Code not tested
 
Upvote 0
Top