Android Question trouble with timer in service

Schakalaka

Active Member
Licensed User
Hello.
with the big help of @LucaMs
i have add on my app, a timer, that work in background when the app is close too.

The app use tlhis class:


Problem1: Solved by OliverA solution: i have change "Duration" from int to long type

sometimes, when i goback to the app, the timer show wrong timer time:
the timer is setted on 5 minutes
This mean that when the bar arrived to 0, the timer continue to go....

1599584330627.png
1599584354846.png


Problem2: Try to implement JohnC solutiono_Oo_O
I have add a txt file in mysafefolder.
on tick sub, it write in the file, and then read the new value from it
Sometime, happend too, that the timer freese inside the app, (and not write on txt (for example at 3:25) and when i return inside, it contuìnue from there...


If need full app code, tell me..

APK FILE TEST IT, All problems should be solved
B4X:
 

Attachments

  • Schaka4.zip
    11.8 KB · Views: 194
Last edited:

JohnC

Expert
Licensed User
Longtime User
No app is guaranteed to keep running in background.

So, when the timer starts, you should record the start time in a file or KeyValue:


Then when your app resumes or the timer ticks, you should display the time as a calculated value based on the current time vs. the stored start time - this way it will always be accurate even if your app is paused in the background.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
This mean that when the bar arrived to 0, the timer continue to go....
That may be caused because the Duration parameter in StartTimer is declared as float. Either declare it as long, or since you are passing it an Int in Main as Int.
 
Upvote 0

Schakalaka

Active Member
Licensed User
Simplest solution is to use B4XPages. The timer will not be paused while in the background (until the complete process is killed).
How can i do it?
i should create a new project?

i have use all above solutions, and add a txt file, where every time the tick write in, but, after close app, it stop writeing.
in debug mode and connected with USB it work fine...

The Apk is here
B4X:
https://drive.google.com/file/d/1jfkst5hOLNmIBMFLtfCWYPFsoJFDuWDH/view?usp=sharing
Source Project:
B4X:
https://drive.google.com/file/d/12EfrUkRd1F6HF9_lCFq2beNNMw_VDKNW/view?usp=sharing
 
Upvote 0

JohnC

Expert
Licensed User
Longtime User
i have use all above solutions, and add a txt file, where every time the tick write in, but, after close app, it stop writeing.
My suggestion was to only write to the text file once when the timer starts so you would save the "start" time in the text file (or keyvalue, etc.)

Then if your timer stops because android closed your app, that's ok because you stored the start time.

Then when your app pops back up to your user on the display (Activity_Resume event triggers), you would load in the start time from the text file and calculate the difference from the start time to now and display the difference, which is the amount of time that has past since the start time.
 
Last edited:
Upvote 0

Schakalaka

Active Member
Licensed User
My suggestion was to only write to the text file once when the timer starts so you would save the "start" time in the text file (or keyvalue, etc.)

Then if your timer stops because android closed your app, that's ok because you stored the start time.

Then when your app pops back up to your user on the display (Activity_Resume event triggers), you would load in the start time from the text file and calculate the difference from the start time to now and display the difference, which is the amount of time that has past since the start time.



something like this?

B4X:
Public Sub StartTimer(Duration As Float)
    If tmr.Enabled Then tmr.Enabled = False
    mGap = 100 / Duration
    Main.gCurrentTime = Duration * 1000
    Log(Main.gCurrentTime)
    tmr.Enabled = True
    File.WriteString(functions.MySafeFolder,"datastore.txt",DateTime.TimeParse(DateTime.Time(DateTime.Now)))
   
End Sub
On timer start, i write on file the current time as string

B4X:
Private Sub tmr_Tick

    If Main.gCurrentTime <= 0 Then
        StopTimer
        Main.gValue = 0
    Else
        
    
        Main.gValue = ((DateTime.TimeParse(DateTime.Time(DateTime.Now))-File.ReadString(functions.MySafeFolder,"datastore.txt")) /1000)*mGap     
        Main.gCurrentTime =     300000 + (File.ReadString(functions.MySafeFolder,"datastore.txt") - DateTime.TimeParse(DateTime.Time(DateTime.Now)) )
        Log(mGap)
        Log(Main.gValue)

    End If
    If Not(IsPaused(Main)) Then
        CallSubDelayed(Main, "UpdateGUI")
    End If
End Sub
On every tick, i calculate the "gcurrentTime", based on the started time that i find on txt file.
i can't calculate this value on MAIN activity, because this value is used for stop the timer too and recive the notification
i calculate also the "gvalue" the progressbar value and base it to the saved value
 
Last edited:
Upvote 0

JohnC

Expert
Licensed User
Longtime User
I can't follow your code 100%, but from what I do think I understand, in the updateGUI sub I would read in the value from the text file and determine the circle value BEFORE assigning a value to the circle because I'm thinking that maybe gValue could be non-zero and could still be wrong if the app went to sleep? But again I don't know where/how gValue is assigned/calculated.
 
Upvote 0

Schakalaka

Active Member
Licensed User
gValue start as 0 when app start,
then become "gValue = gValue + mGap" where mGap = 100 / Duration (duration = 300)
 
Upvote 0

Schakalaka

Active Member
Licensed User
@Erel save me. 🙏🙏
i have "copy and paste" the b4a project into b4X Pages, but i have a problem with drawer left menu

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
*** Service (srvcircularpb) Create ***
** Service (srvcircularpb) Start **
Consent state: PERSONALIZED
EU: true
*** Service (firebasemessaging) Create ***
** Service (firebasemessaging) Start **
Error occurred on line: 548 (B4XPagesManager) <-----
java.lang.RuntimeException: Object should first be initialized (JavaObject).
    at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:67)
    at anywheresoftware.b4j.object.JavaObject.getCurrentClass(JavaObject.java:258)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:118)
    at com.clickandclaim.android.b4xmainpage$ResumableSub_B4XPage_Appear.resume(b4xmainpage.java:140)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:48)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:43)
    at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1704)
    at android.os.Handler.handleCallback(Handler.java:808)
    at android.os.Handler.dispatchMessage(Handler.java:101)
    at android.os.Looper.loop(Looper.java:166)
    at android.app.ActivityThread.main(ActivityThread.java:7523)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

on debug, the error is related with this code on Main:confused::confused::confused:

Main page
B4X:
Sub Activity_Resume
    B4XPages.Delegate.Activity_Resume
End Sub


B4X:
https://drive.google.com/file/d/1IZhq2g57xg9fbckHvlUS2vaU2ug-hqhD/view?usp=sharing

Library
1600876831531.png
1600876860785.png
 
Upvote 0
Top