Italian Dopo Wait For (ResumableSub) il codice non prosegue con l'istruzione successiva

Sabotto

Active Member
Licensed User
Ho questo codice
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("layMainTurno")
    If FirstTime Then 'Solo la prima volta
        OperazioniIniziali
    End If
    GetTurnoGiornoAndShow
End Sub

Sub OperazioniIniziali
    Wait for (DownloadFileTurno1) complete (Result As Boolean)
    RicavaRigheTurni
    Giorno=DateTime.GetDayOfMonth(DataOggi)
End Sub

Sub DownloadFileTurno1() As ResumableSub 
    NomeFileTurno = NomeMese & (Anno Mod 2000) & ".TEL"
    dbxFiles.download(File.Combine(DirTurni_DropBox,NomeFileTurno), DirDestination, NomeFileTurno)
    Do While File.Size(DirDestination,NomeFileTurno)=0
            Log("file non ancora scaricato del tutto")
     Loop
     Return True
End Sub

Sub GetTurnoGiornoAndShow
    RicavaTurnoDelGiorno
    MostraTurni
 End Sub

Sub RicavaTurnoDelGiorno
    
 For i = 0 To 5
        TurnoDelGiorno(i)=RigaTurno(i).SubString2(Giorno-1,Giorno)
 End Sub

In debug passo passo, dopo la chiamata
B4X:
Wait for (DownloadFileTurno1) complete (Result As Boolean)
il codice non continua con la chiamata alla routine RicavaRigheTurni (che si trova subito dopo la Wait For), ma salta alla prima istruzione di RicavaTurnoDelGiorno (che è la prima routine chiamata da GetTurnoGiornoAndShow)!!!
Npn capisco perchè?!
 

udg

Expert
Licensed User
Longtime User
A naso direi che dipenda dal fatto che OperazioniIniziali sia nella "FirstTime" e quindi, a parte la prima volta che l'activity viene creata (o ricreata), si passa direttamente a GetTurnoAndShow che appunto richiama RicavaTurnodelGiorno
 

Star-Dust

Expert
Licensed User
Longtime User
Credo che sia pure sbagliato usare il DoWhile per verificare se ha scaricato il file da Dropbox. Creerà un blocco. In ogni caso dentro il doWhile sarebbe necessario il deprecato DoEvents.
Ma sarebbe meglio usare Wait For.

Inoltre OperazioniIniziali passa subito a GetTurnoGiornoAndShow , a motivo del Wait for che rimane in attesa e passa al livello successivo.

Richiede un ulteriore WaiFor Complete per OperazioniIniziali
 
Last edited:

udg

Expert
Licensed User
Longtime User
Concordo.
Per le inizializzazioni è bene avere una serie di wait for in modo da essere certi che ogni step sia completato prima di passare al successivo. Un eventuale errore/problema potrebbe essere gestito per inibire la prosecuzione verso "ormai inutili" passaggi. Un esempio banale è un'app che necessita di collegamento Internet. Se manca quello, inutile proseguire, no? Messaggino e via. L'utonto provvederà a spostarsi dove troverà sufficiente ricezione e lancerà nuovamente l'app.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
WaitFor e Sleep(0) non sono proprio facili da usare, poichè non mettono il programma in attesa (come ci si aspetterebbe) ma eseguono un "return" alla funzione chiamata e poi rientrano in azione esattamente dalla riga successiva quando la condizione è avvenuta.

Molto pericoloso quindi usarli sul Activity_Create e in più routine contemporaneamente (come hai fatto tu).

Vediamo se riesco a farmi capire:
Quando Activity_Create parte, FirstTime è true, e quindi viene chiamata OperazioniIniziali.
Su OperazioniIniziali viene eseguito un WaitFor, ma come ti ho già detto non mette in attesa l'esecuzione, ma esegue un return, e quindi il controllo ritorna a Activity_Create, che prosegue chiamando GetTurnoGiornoAndShow che a sua volta chiama RicavaTurnoDelGiorno (senza che il WaitFor abbia finito)

Come vedi il flow del programma è giusto come te lo trovi tu.

So che è brutto e non va fatto, ma in alcuni casi è ancora utile il deprecato DoEvents (che quindi come hai capito in certi casi non può essere sostituito con Sleep(0) proprio per questi problemi).

In alcuni punti dei miei programmi utiizzo ancora DoWhile con il DoEvents (con un timeout di sicurezza) per non mandare il tutto in blocco.
Stesso discorso per MsgBox, che anche lui è deprecato e quindi sconsigliato, ma in alcune situazioni è ancora indispensabile.

Il debug passo-passo, con i Wait For, è praticamente impossibile. Si devono usare i Log.

Verissimo !!!!!!
 

Star-Dust

Expert
Licensed User
Longtime User
Lo Sleep(0) non sostituirebbe correttamente il DoEvents. Farebbe ritornare su il flusso dell'esecuzione
Mentre con il DoWhile va messo DoEvents perche il flusso rimanga finche non si verifichi la condizione.

Piuttosto che mettere uno Sleep(0) dentro il DoWhile che non svolgerebbe il lavoro giusto, meglio fare più correttamente un WaitFor () Complete
 
Last edited:

sirjo66

Well-Known Member
Licensed User
Longtime User
prova questo:
(solo per una prova, il codice non è comunque corretto)
B4X:
Sub OperazioniIniziali
    DownloadFileTurno1
    RicavaRigheTurni
    Giorno=DateTime.GetDayOfMonth(DataOggi)
End Sub

Sub DownloadFileTurno1()
    NomeFileTurno = NomeMese & (Anno Mod 2000) & ".TEL"
    dbxFiles.download(File.Combine(DirTurni_DropBox,NomeFileTurno), DirDestination, NomeFileTurno)
    Do While File.Size(DirDestination,NomeFileTurno)=0
           DoEvents
            Log("file non ancora scaricato del tutto")
     Loop
     Return True
End Sub
 

Star-Dust

Expert
Licensed User
Longtime User
Farei una cosa simile:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   ' Activity.LoadLayout("layMainTurno")
    If FirstTime Then 'Solo la prima volta
        Wait For (OperazioniIniziali) complete (Result As Boolean)
        If Result=False then log("File non scaricato")
    End If

    If  File.Exists(DirDestination,NomeFileTurno) AND File.Size(DirDestination,NomeFileTurno)>0 then
       GetTurnoGiornoAndShow
    End If
End Sub

Sub OperazioniIniziali As ResumableSub
    Wait for (DownloadFileTurno1) complete (Result As Boolean)
    If Result then
        Giorno=DateTime.GetDayOfMonth(DataOggi)
        'RicavaRigheTurni
    End If

    Return Result
End Sub

Sub DownloadFileTurno1() As ResumableSub
    NomeFileTurno = NomeMese & (Anno Mod 2000) & ".TEL"
    dbxFiles.download(File.Combine(DirTurni_DropBox,NomeFileTurno), DirDestination, NomeFileTurno)

    Wait For dbxFiles_DownloadFinished(success As Boolean, meta As FileMetadata, error As String)
    ' Non so se è corretto questo evento

    Return success
End Sub

Sub GetTurnoGiornoAndShow
    RicavaTurnoDelGiorno
    MostraTurni
End Sub

Sub RicavaTurnoDelGiorno
For i = 0 To 5
        TurnoDelGiorno(i)=RigaTurno(i).SubString2(Giorno-1,Giorno)
Next
End Sub
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
prova questo:
(solo per una prova, il codice non è comunque corretto)
B4X:
Sub OperazioniIniziali
    DownloadFileTurno1
    RicavaRigheTurni
    Giorno=DateTime.GetDayOfMonth(DataOggi)
End Sub

Sub DownloadFileTurno1()
    NomeFileTurno = NomeMese & (Anno Mod 2000) & ".TEL"
    dbxFiles.download(File.Combine(DirTurni_DropBox,NomeFileTurno), DirDestination, NomeFileTurno)
    Do While File.Size(DirDestination,NomeFileTurno)=0
           DoEvents
            Log("file non ancora scaricato del tutto")
     Loop
     Return True
End Sub

Return True, in DownloadFileTurno1 non serve se non usi le WaitFor. Non s aspetta la restituzione di un valore
 

Sabotto

Active Member
Licensed User
Innanzitutto grazie a tutti della partecipazione alla discussione.
premesso che farò le varie prove suggerite, charisco solo una cosa. Più di uno di voi mi dice in pratica (uso la citazione di SirJo)

"Su OperazioniIniziali viene eseguito un WaitFor, ma come ti ho già detto non mette in attesa l'esecuzione, ma esegue un return, e quindi il controllo ritorna a Activity_Create che prosegue chiamando GetTurnoGiornoAndShow..."

Ma qesta cosa è vera con il Wait For semplice, ma usando una "ResumableSub", e chiamandola con il complete
B4X:
Wait for (DownloadFileTurno1) complete (Result As Boolean)
non dovrebbe aspettare che ritorni appunto un risultato dalla sub DownloadFileTurno1???
Allora a che serve la resumable Sub? Che difefrensa c'è con una Sub Normale che restituisce un valore?

Se fate questo test

B4X:
Sub Test()
Wait for (SubTipoResumable) complete (Result As Boolean)
Log("sono qui dopo aver aspettato i 5 secondi")
End Sub

Sub SubResumable() as ResumableSub
    sleep(5000)
    return True
End Sub

il Log avviene esttamente dopo 5 secondi, quindi vuol dire che il Wait For ha aspettato.

Ma poi, anche se fosse, (che non aspetta) dovrebbe eseguire l'istruzione immediatamente successiva che è RicavaRigheTurno, e NON uscirsene dalla Sub!!! (o no?)

Dovrebbe quindi essere:
"...ritorna a Activity_Create, che prosegue chiamando RicavaRigheTurno..."
e NON
.
"...ritorna a Activity_Create, che prosegue chiamando GetTurnoGiornoAndShow ..."
 
Last edited:

udg

Expert
Licensed User
Longtime User
Sia Wait For che Sleep producono in prima istanza lo stesso effetto di un Return
Nel tuo test, quando il waitfor chiama la sub con lo sleep attiva una catena di eventi tipo
- waitfor (sospendo Test fino al complete)
- sleep (sospendo sub2 finchè non passano i 5s)
- torno a test ma waitfor non è completa quindi "aspetto" (la UI funziona e Resume viene eseguita)
- sleep termina il conteggio dei 5s
- la sub con sleep viene riattivata e completata
- test viene riattivato e completato (stampando il log)

Come giustamente diceva @LucaMs , avere un waitfor nella Create fa sì che questa venga "sospesa" e si prosegua con la Resume (che presumo non essere ciò che desideri). Meglio da create chaimare una sub Inizializza in cui avere una serie di waitfor. In questo caso avrai: Create-Inizializza(solo fino al primo wait)-Resume-Ping Pong tra Inizializza e sub richiamate- Fine di Inizializza.
 
Last edited:

sirjo66

Well-Known Member
Licensed User
Longtime User
non dovrebbe aspettare che ritorni appunto un risultato dalla sub DownloadFileTurno1???

ResumableSub, Sleep e WaitFor funzionano sostanzialmente nella stessa maniera.
Quando il programma incontra un Sleep o un WaitFor non fa altro che creare un punto sul programma (la riga dopo il WaitFor o lo Sleep) che verrà chiamato quando l'evento accade.
A questo punto fa un "return" e ritorna alla sub chiamante e prosegue nel suo lavoro.
Devi quindi pensare il tutto non come un flusso continuo ma una gestione event-driven, cioè ad eventi.

Sul post di Erel https://www.b4x.com/android/forum/threads/b4x-resumable-subs-sleep-wait-for.78601/ trovi delle info, vedi soprattutto la riga che dice:
Whenever Sleep or Wait For are called, the current sub is paused. This is equivalent to calling Return.
 
Last edited:

Sagenut

Expert
Licensed User
Longtime User
Allora a che serve la resumable Sub? Che difefrensa c'è con una Sub Normale che restituisce un valore?
Una ResumableSub può essere chiamata più volte, senza attendere che sia finita la prima chiamata, e ogni chiamata verrà gestita in parallelo alle altre.
Il risultato di ogni chiamata verrà assegnato correttamente alle varie richieste.
Lo puoi vedere bene nel video tutorial delle ResumableSubs:
5 immagini vengono scaricate prima normalmente, ovvero in sequenza una dopo l'altra.
Poi vengono scaricate tutte in contemporanea chiamando subito 5 volte la stessa Sub.
 
  • Like
Reactions: udg

sirjo66

Well-Known Member
Licensed User
Longtime User
perchè hai definito
B4X:
Sub DownloadFileTurno1() As ResumableSub
quando al suo interno questa sub non contiene nessun WaitFor ??
 

Sagenut

Expert
Licensed User
Longtime User

sirjo66

Well-Known Member
Licensed User
Longtime User
Quella dichiarazione mi pare sia necessaria per poter fare ritornare un valore da una ResumableSub.

Il problema è che la DownloadFileTurno1 NON è una ResumableSub, è quello che sto tentando di dire da un po'.
Le ResumableSub hanno una iconcina sulla destra della dichiarazione (un piccolo cerchietto con una freccina), non basta mettere "As ResumableSub" nella dichiarazione.

Per cui la linea
Wait for (DownloadFileTurno1) Complete (Result As Boolean)
non funziona correttamente poichè non essendo una ResumableSub reale, l'evento "Complete" non funziona correttamente.
 

Sagenut

Expert
Licensed User
Longtime User
Non avevo guardato la sua Sub.
Basta un as Boolean.
Ma la sintassi non sarebbe comunque quella per ricevere un risultato anche da una Sub normale?
 

Star-Dust

Expert
Licensed User
Longtime User
Il problema è che la DownloadFileTurno1 NON è una ResumableSub, è quello che sto tentando di dire da un po'.
Le ResumableSub hanno una iconcina sulla destra della dichiarazione (un piccolo cerchietto con una freccina), non basta mettere "As ResumableSub" nella dichiarazione.

Per cui la linea
Wait for (DownloadFileTurno1) Complete (Result As Boolean)
non funziona correttamente poichè non essendo una ResumableSub reale, l'evento "Complete" non funziona correttamente.
Come l'ha scritta lui non è resumable sub. Usa DoWhile anzichè una WaitFor
 
Top