Italian Circle ProgressBar Basata su Timer

Schakalaka

Active Member
Licensed User
Longtime User
WOW! :eek::eek::eek:

quanti commenti!
non mi son arrivate le mail di notifica e ho visto solo ora

Lavoro magnifico!!! mi sembra ?????


Ho sistemato la dimensione del testo ed fatto in modo che venga controllato che la editext non sia vuota

B4X:
https://drive.google.com/file/d/1Y5-DotodYXxB6m6CcUjeKNzieCj-Dp69/view?usp=sharing


Non pensavo che questa discussione arrivasse a 3 pagine di commenti ?
 

Schakalaka

Active Member
Licensed User
Longtime User
un altro piccolo dettaglio vorrei aggiungere.
devo manterere il timer attivo anche quando esco dalll' app o blocco lo schermo.
suppongo che devo agire sull' Activity_Pause, per ottenere ciò...
 

Schakalaka

Active Member
Licensed User
Longtime User
quindi devo avviare il timer nella tab Starter?

quando blocco lo schermo quando il timer è attivo mi appare questo come log:


** Activity (main) Pause, UserClosed = false **
Sleep not resumed (context is paused): anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub


mai usato la tab servizi

ho provato anche questo esempio di timer, ma funziona anche ad app chiusa:

 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Ti dò una bella (spero) risposta lunga, così anche @Star-Dust sarà contento (e dirà che ho deviato dalla domanda ? - no, in realtà non ti consiglierò una cosa diversa da quanto già fatto in preDecenza).

Vorrei chiarirti la cosa del "tab Starter", come lo hai chiamato. I Tab che vedi sopra, come lo Starter, sono i tuoi moduli di progetto, che possono essere di diverso tipo:

Activity
Services (servizi - come lo Starter)
Code modules (moduli di codice)
Class modules (moduli di classe o più semplicemente "classi")

Quindi, quello che avresti dovuto chiedere, anziché:
quindi devo avviare il timer nella tab Starter?

Sarebbe dovuto essere: "quindi devo avviare il timer nel servizio Starter?"
(Non ti sto correggendo, voglio solo farti notare cosa contiene il tab Starter).

Il timer va creato ed utilizzato all'interno di un modulo di servizio (nel tuo caso, perché vuoi che esso continui a "lavorare" anche se la tua app non è visibile sullo schermo), ma il modulo di servizio Starter non va bene per questo, se vuoi che il servizio rimanga attivo anche per ore. Per quest'ultima cosa, per far funzionare a lungo il servizio senza che Android lo "uccida", bisogna seguire un esempio di Erel: Background location tracking.

Andando in ordine, prima vediamo come dovrebbe funzionare il timer in un modulo di servizio ma aggiornando la grafica di un'Activity (nel tuo caso far avanzare la CircularProgressBar). "Semplicemente" l'evento Tick del timer, che come tutto il codice che riguarda il timer starà nel modulo di servizio (chiamiamolo srvCircularPB), dovrà chiamare una routine che si trovi nell'Activity e che aggiorni la grafica (la tua CPB).

Dato che attualmente la CPB viene aggiornata nella routine-evento tmr_Tick (o come l'hai chiamata, non so) della tua Main, dovrai chiamare questa (cambiagli nome, chiamala soltanto "Tick", magari, e dovrai eliminare l'oggetto timer nella Main - la sua dichiarazione e inizializzazione).

[Per aggiungere un nuovo modulo di servizio al tuo progetto]
1589508626301.png


Mettiamo che nel modulo di servizio srvCircularPB tu abbia dichiarato un timer di nome "tmr":
B4X:
CallSubDelayed(Main, "Tick")
lancerà appunto la routine "Tick" della Main.

Direi che, fin qui, il tuo modulo di servizio srvCircularPB potrebbe essere più o meno così:
B4X:
Sub Process_Globals
    Private tmr As Timer
End Sub

Sub Service_Create
    tmr.Initialize("tmr", 1000)
End Sub

Public Sub StartTimer(Duration As Float)
    If tmr.Enabled Then tmr.Enabled = False
    tmr.Enabled = True
End Sub

Public Sub StopTimer
    tmr.Enabled = False
End Sub

Private Sub tmr_Tick
    CallSubDelayed(Main, "Tick")
End Sub

Intanto prova così; se non funziona, e se puoi, allega il progetto.

Anzi, ho sospeso la scrittura di questo luuuungo post, ho preso una vecchia versione di @Sagenut, e l'ho modificata come ti ho appena spiegato (ma tu prima prova a farlo da solo, seguendo quanto scritto sopra).

Manca ancora la parte che "dovrebbe" salvare il tuo servizio dall'uccisione da parte di Android (quella per la quale ti ho suggerito il tutorial di Erel, Background location tracking), ma per il momento... mi sarei rotto qualcosa ?
 

Attachments

  • 1.zip
    10.8 KB · Views: 201
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Avete presente il doppio-click? Ecco, per un post come il preDecente dovrebbe esistere anche il doppio-Like ?

Chissà, magari metto anch'io un bel tasto [Donate] nella mia signature; scommetto che moltissimi membri di b4x, italiani e non, si affretterebbero a donare come minimo 1.000€ ogni mese ?
 

Schakalaka

Active Member
Licensed User
Longtime User
grazie per la luuunga spiegazione.
qualcosa avevo già intuito, e guardato proprio quel post..

Ho anche provato il tuo esempio.
il "problema", è che il timer, se è in background non si ferma, e quando riapro, il timer ha valore negativo.
succede probabilmente perchè quando l' app non è aperta, il servizio non accede ogni volta alla sub, ma la tiene in memoria, e quindi "salta" il controllo all' interno :oops: :oops: ? ? ???


Ho aggiunto anche l' invio di una notifica.

Il risultato finale dovrebbe essere che alla fine dei 5 minuti, arriva la notifica.
con app aperta o chiusa.
 

Attachments

  • 1.zip
    11.3 KB · Views: 205

LucaMs

Expert
Licensed User
Longtime User
Non ho ancora lanciato il tuo progetto ma guardando il sorgente... Hai creato una routine CreateNotification nel srvCircularPB ma poi nella routine StopTimer hai scritto:

CallSubDelayed(Main, "CreateNotification")

ovvero cerchi di far eseguire al Main una routine che non ha.

Inoltre, la tua routine CreateNotification richiede un parametro stringa Body (ovvero il testo della notifica), che non gli passi.

Più tardi guarderò anche le altre faccende.
 

LucaMs

Expert
Licensed User
Longtime User
il "problema", è che il timer, se è in background non si ferma, e quando riapro, il timer ha valore negativo.
Di nuovo, ancora non l'ho lanciato, ma ho visto perché questo accade. Perché la routine Tick del Main ovviamente non va in esecuzione, se l'app non è attiva.
Il timer prosegue il proprio "lavoro", ma quella routine non andrà in esecuzione, ed è in quella che viene incrementato il valore della CPB ed anche controllato se sia arrivato a 100.

Va modificato un bel po' (non va bene nemmeno il tentativo di rendere il servizio "non ammazzabile" da Android).

Ora non è il momento, per me; se questa indicazione ti basta per modificarlo (suggerimento: i calcoli vari vanno fatti nel servizio)... Altrimenti proverò più tardi.
 

Schakalaka

Active Member
Licensed User
Longtime User
Grazie per l' esempio.
Funziona, ma dopo 21 "tick", esce anche questo messaggio nel log.
"Ignoring event (too many queued events: CallSubDelayed - UpdateCPB)"

e quando riapro l' app, il timer mostra un numero sbagliato.
io provato con 60 secondi.


Azzardo un' ipotesi:
si potrebbe inserire la chiamata a CallSubDelayed - UpdateCPB in una lista, ed ogni 20 chiamate, eseguire e pulire la lista (anche se non so se sia il contenitore giusto e se se possa fare come ho pensato...).


se l' app viene riaperta prima della scadenza del timer, viene eseguito comunque l' aggiornamento della barra.
 

LucaMs

Expert
Licensed User
Longtime User
Si può fare in un altro modo: controllare che la Main sia attiva, prima di eseguire la CallSubDelayed:
B4X:
If Not(IsPaused(Main)) Then
    CallSubDelayed3(Main, "UpdateCPB", mCPBValue, mCurrentTime)
End If
 

Schakalaka

Active Member
Licensed User
Longtime User
boh, se inserisco 300 secondi, il timer non parte, se ne inserisco 60, funziona.
Non sempre quando si riapre l' app, la barra è "sincronizzata con timer.
ho tolto l' editext dove inserire i secondi e ho dato il valore 300 a "duration" di default
 
Last edited:

Schakalaka

Active Member
Licensed User
Longtime User
Siccome riaprendo l' app, a volte la barra era nel posto sbagliato, e faceva andare il timer in negativo, fin quando non raggiungeva il valore 100, ho modificato il codice "Tick, in questo modo:

B4X:
Private Sub tmr_Tick
    If mCPBValue >= 100 Or  mCurrentTime = 0 Then
        StopTimer
        mCPBValue = 0
    Else
        mCPBValue = mCPBValue + mGap
        mCurrentTime = mCurrentTime - 1000
    End If
    CallSubDelayed3(Main, "UpdateCPB", mCPBValue, mCurrentTime)
    Log(modMyUtils.ConvertTicksToTimeString(mCurrentTime))
End Sub

Soluzione forse un po "rozza", ma funzionale

se inserisco il valore 300, il timer parte, ma la barra no.
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Devi comunque usare:
B4X:
If Not(IsPaused(Main)) Then
    CallSubDelayed3(Main, "UpdateCPB", mCPBValue, mCurrentTime)
End If

Altrimenti supera (può superare) il numero massimo di "accodamento", che a quanto pare è 20.
 

Schakalaka

Active Member
Licensed User
Longtime User
che sia piu semplice usando questa?
B4X:
https://www.b4x.com/android/forum/threads/b4x-xui-gauge-view.87435/
ed invece di mostrare il timer, la percentuale di completamento.
Sempre 5 minuti di durata e timer come servizio..

(p.s: per caso usi i reward video in qualche tua app? è il prossimo problema da risolvere..)
 

LucaMs

Expert
Licensed User
Longtime User
che sia piu semplice usando questa?
Non so se sia più semplice, probabilmente avresti gli stessi problemi - tutto sta a far fare bene i calcoli nel servizio e richiamare l'aggiornamento della View (qualunque essa sia) nell'Activity.


(p.s: per caso usi i reward video in qualche tua app? è il prossimo problema da risolvere..)
No, ma lo farò e, soprattutto, lo feci per prova ("oggi" non potrei provare, in quanto ho l'account AdMob momentaneamente non funzionante, per motivi tecnici).
Apri un nuovo thread su questo argomento e ti verrà risposto sicuramente.
 
Top