Android Question Jerky Animation (2)

RJB

Active Member
Licensed User
Longtime User
I asked a question quite some time ago which was never really resolved and I'm looking at it again now. Using the animation library can give jerky results, particularly on older/ slower devices. In this example the text 'jumps' to varying degrees according to what device is used:
B4X:
Sub Globals
    Dim animate1 As Animation
    Dim SText As EditText
End Sub
Sub Activity_Create(FirstTime As Boolean)
    SText.Initialize("")
    SText.Text = "the quick brown fox jumps over the lazy dog"
    SText.TextSize = 150dip
    Activity.AddView(SText,800dip,10dip, 4500dip,300dip)
    animate1.InitializeTranslate("animations",0,0,-SText.Width,0)
    animate1.duration = 10000
    animate1.RepeatCount= -1
    animate1.RepeatMode = animate1.REPEAT_REVERSE
    animate1.Start(SText)
End Sub
It appears that there are two type of animation in Android, View and Property. The animation library seems to use View animation.
Has anyone used Property animation? Are there any examples in B4A? Is it likely that it would improve the smoothness of animation over View animation?
Thanks
 

RJB

Active Member
Licensed User
Longtime User
View.SetLayoutAnimated is based on property animation.

Both types of animations should be smooth. Maybe it is something else in your program that slows down the animation.

Is this the complete code?

Thanks, I'll experiment with SetLayoutAnimated.
That was just some code to demonstrate the problem. It is the complete code of that demonstration and does show the problem, particularly on older/ slower devices. I've done a factory reset on a couple of devices to ensure it's nothing I've done that is causing the problem.
The previous question (about two years ago) showed the interaction between other code and the timers/ animations in the same app.
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
The following:
B4X:
Sub Globals
    Dim SText As EditText
    Dim animatetimer As Timer
    Dim x As Boolean = True
End Sub

Sub Activity_Create(FirstTime As Boolean)

    SText.Initialize("")
    SText.Text = "the quick brown fox jumps over the lazy dog"
    SText.TextSize = 150dip
    Activity.AddView(SText,800dip,10dip, 4500dip,300dip)

    animatetimer.Initialize("animatetimer", 1000)
    animatetimer.Enabled = True

End Sub

Sub animatetimer_tick
    animatetimer.Interval = 10000
    If x Then
        SText.SetLayoutAnimated(10000, (SText.Left - SText.Width) * 1dip, 10dip, 4500dip, 300dip)
    Else
        SText.SetLayoutAnimated(10000, (SText.Left + SText.Width) * 1dip, 10dip, 4500dip, 300dip)
    End If
    x = Not(x)
End Sub

Gives the same result, or even slightly worse, so not a lot of point in pursuing property animation.
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
are you testing this in debug mode? try again in release mode and it should be more smooth.
 
Upvote 0

mangojack

Well-Known Member
Licensed User
Longtime User
I tried this (code @post #4) on 2 devices .. Samsung s2 phone 4.1.2 , Samsung Tablet SMT530 5.02 in both debug and release.
I consider the animation quite smooth (and effective). there seemed to be a very minor 'skip' on the pad occasionally at about the midway mark,
but hardly noticeable IMO. the phone very smooth ??
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
are you testing this in debug mode? try again in release mode and it should be more smooth.
Debug, Release and Release obfuscated, on four different devices, a phone, a tablet, an MX TV box and an M8 TV box, with hardware acceleration enabled in the manifest and in the options, etc.
The amount of 'skipping' varies between the devices but on none is it acceptable for a professional app. And it gets worse if the app is doing anything else at the same time. Presumably it is caused by other things (services?) happening on the device at the same time?
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Both Animation and SetLayoutAnimated are based on the native animation features of Android.

There is no other or better way to create animations in Android.
Probably caused by the same thing that makes timers so inaccurate!
Is there any way to 'isolate' the animation, e.g. as a service or in another thread, that will improve things?
Thanks
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Probably caused by the same thing that makes timers so inaccurate!
You made a strong argument so I decided to test it.
B4X:
Sub Process_Globals
   Private timer1 As Timer
   Private LastTick As Long
   Private counter As Int
   Private accumulatedError As Int
End Sub

Sub Globals
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     timer1.Initialize("Timer1", 100)
     timer1.Enabled = True
     LastTick = DateTime.Now
   End If
End Sub

Sub Timer1_Tick
   counter = counter + 1
   Dim diff As Int  = Abs(DateTime.Now - LastTick - timer1.Interval)
   accumulatedError = accumulatedError + diff
   Log($"Average error: $1.2{accumulatedError / counter} ms"$)
   LastTick = DateTime.Now
End Sub
The results are better than I expected. The average error is 0.5 milliseconds (500 microseconds).

I've tested it on a Nexus 5 (in release mode).
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
You made a strong argument so I decided to test it.
B4X:
Sub Process_Globals
   Private timer1 As Timer
   Private LastTick As Long
   Private counter As Int
   Private accumulatedError As Int
End Sub

Sub Globals
 
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     timer1.Initialize("Timer1", 100)
     timer1.Enabled = True
     LastTick = DateTime.Now
   End If
End Sub

Sub Timer1_Tick
   counter = counter + 1
   Dim diff As Int  = Abs(DateTime.Now - LastTick - timer1.Interval)
   accumulatedError = accumulatedError + diff
   Log($"Average error: $1.2{accumulatedError / counter} ms"$)
   LastTick = DateTime.Now
End Sub
The results are better than I expected. The average error is 0.5 milliseconds (500 microseconds).

I've tested it on a Nexus 5 (in release mode).

Hi,
I only just saw this. I don't know why I didn't get an email when it was posted.

The problems seem to come when there is other code running at the same time. I would think that the timer would be interrupt driven with a very high priority so that it remained accurate but that doesn't seem to be the case. Also the problem is (in my case) with the maximum error rather than the average (and the same would apply to scrolling).
Modifying the code to:

B4X:
Sub Process_Globals
   Private timer1 As Timer
   Private LastTick As Long
   Private counter As Int
   Private accumulatedError As Int
   Private MaxError As Int = 0
 
End Sub

Sub Globals
    Dim Output As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     timer1.Initialize("Timer1", 100)
     timer1.Enabled = True
     LastTick = DateTime.Now
   End If
   Output.Initialize("")
   Activity.AddView(Output, 10dip, 10dip, 300dip, 50dip)
End Sub

Sub Timer1_Tick
   counter = counter + 1
   Dim diff As Int  = Abs(DateTime.Now - LastTick - timer1.Interval)
   accumulatedError = accumulatedError + diff
'   Log($"Average error: $1.2{accumulatedError / counter} ms"$)
   If diff > MaxError Then MaxError = diff
   Output.Text ="max= " & MaxError & "mS, Av= " & Round2(accumulatedError / counter, 2) & "mS"
   LastTick = DateTime.Now
End Sub

gives a maximum of between 2 and 8 times the average depending of the device, and presumably worse if other code were running.
Is there any way to improve the priority of the timer/ scrolling?

Thanks
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Priority is not relevant here. The timer events are executed by the main thread. They will never happen when the main thread is busy with other code.

My guess is that the real problem is somewhere else. You need to find out which code in your app slows down the main thread and see how it can be optimized.


Sorry to be a pain, I know the problem lays with Android, not B4A, so I doubt there is going to be anything we can do!

The above code shows the problem and as far as I can see there is only the timer running so nothing to optimise!
To provide more insight I've changed the code to:

B4X:
Sub Process_Globals
   Private timer1 As Timer
   Private LastTick As Long
   Private counter As Int
   Dim ThisTick As Long
   Private FirstTick As Int
   Private MaxTick As Int = 0
   Private MinTick As Int = 0
   Dim const TargetTick As Int = 1000

End Sub

Sub Globals
    Dim Output As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     timer1.Initialize("Timer1", TargetTick)

   End If
   Output.Initialize("")
   Activity.AddView(Output, 10dip, 10dip, 300dip, 50dip)
End Sub

Sub Activity_Resume
    counter = 0
    FirstTick = 0
     MaxTick = TargetTick
     MinTick = TargetTick
     LastTick = DateTime.Now
     timer1.Enabled = True
End Sub

Sub Activity_Pause (UserClosed As Boolean)
     timer1.Enabled = False
End Sub

Sub Timer1_Tick
    ThisTick = DateTime.now - LastTick
    LastTick = DateTime.now
    If counter = 0 Then
        FirstTick = ThisTick
    Else
        If ThisTick > MaxTick Then MaxTick = ThisTick
        If ThisTick < MinTick Then MinTick = ThisTick
    End If

    counter = counter + 1
    Output.Text = " T= " & TargetTick & " F= " & FirstTick & " M= " & MaxTick & " m= " & MinTick & " C= " & counter
End Sub

Different devices give different figures but a typical set is as follows:
T= 1 F= 39 M= 33 m= 0
T= 10 F= 35 M= 43 m= 9
T= 100 F= 101 M= 112 m= 99
T= 1000 F= 1001 M= 1002 m= 1000
 
Last edited:
Upvote 0
Top