Italian CallSub & CallSubDelayed

giannimaione

Well-Known Member
Licensed User
Longtime User
ciao ragazzi,
che mi spiega l'uso e l'utilità dei vari callsub .. callsub2... callsubdelayd.. ecc.
possibilmente con esempi in B4J
 

LucaMs

Expert
Licensed User
Longtime User
Ci provo io, per quel che mi ricordo e per quanto sia in grado di farlo in questo momento :)

Spesso puoi farne a meno perché basta invocare il nome del metodo:
1) quando la routine è nello stesso modulo dal quale invochi il metodo
2) quando invochi il metodo di un modulo di codice o di un oggetto, premettendone il nome (modUtilty.NomeRoutine)

Devi invece usare CallSub per chiamare routine che si trovino in un modulo di servizio (se la chiamata non viene fatta dall'interno del modulo stesso, cioè da un'Activity, ad esempio).

CallSubDelayed (Delayed sta per ritardato, non nel senso che ha avuto problemi di crescita :D) significa che l'esecuzione della routine avviene in maniera posticipata, ovvero la routine viene eseguita soltanto dopo che saranno state eseguite le eventuali istruzioni che la seguono e che fanno parte della routine dalla quale chiami la routine esterna (pessima spiegazione ma bastano due righe di codice di esempio):

B4X:
Sub RoutinePrincipale
    log(1)
    CallSubDelayed(Me, "RoutineSecondaria") ' Me se RoutineSecondaria è nello stesso modulo
    log(2)
End Sub

Sub RoutineSecondaria
    log(3)
End Sub

log(2) verrà eseguita prima di log(3) e quindi otterrai:
1
2
3

Se avessi chiamato la routine direttamente o usato CallSub:
1
3
2

Unica altra cosa che mi viene in mente è una differenza tra CallSubDelayed usata in B4J rispetto a B4A. In B4J la routine chiamata verrà eseguita nel thread che la contiene, in B4A sarà eseguita nel thread che esegue la chiamata.



Ah, le varie versioni 2 e 3 servono per passare parametri alla routine.

Se la routine da chiamare richiedesse un parametro, dovresti usare una versione 2:
B4X:
CallSubDelayed2(Me, "Visualizza", "Ciao") ' oppure CallSub2
'''''

Sub Visualizza(Parola As String)


Se ne richiedesse due, dovresti usare una versione 3:
B4X:
CallSubDelayed3(Me, "Somma", 50, 25)
'''

Sub Somma(A As Int, B As Int)


Se la routine da chiamare richiedesse un Array:
B4X:
CallSubDelayed2(Me, "VisualizzaTutto", Array As Object(1,"ciao",2))
'''''

Sub VisualizzaTutto(Dati() As Object)
   For i = 0 To Dati.Length - 1
     Log(i & TAB & Dati(i))
   Next
End Sub
 
Last edited:

giannimaione

Well-Known Member
Licensed User
Longtime User
ciao Luca,
il problema è questo.
ho creato una APPlicazione in B4J ed è funzionante!
tramite ftp prelevo dei files ,mediamente circa 15-20 files, contenete stringhe tipo:
INSERT INTO PREZZIC (CODART,QTA,PREZZO,RIF,DMOV,CODCLI,SC1,SC2,SC3,IDKEY) VALUES ('00200375','2','7.849','FT00239 del 11/01/2016','160111','2815','10','3','','2815002003751')
all'interno dei singoli file queste stringhe si possono ripetere (con valori diversi) anche per centinaia di volte... in pratica il file di solito contiente anche 200,300 righe.
poi processo il tutto con
B4X:
Dim Reader As TextReader
     Reader.Initialize(File.OpenInput(PathLocale, NomeFile))
     Dim line As String
   Try
     Main.sqlt.BeginTransaction
       line = Reader.ReadLine
       Do While line <> Null
       Main.sqlt.ExecNonQuery(line)
       line = Reader.ReadLine
       Loop
       Reader.Close
     Main.sqlt.TransactionSuccessful
   Catch
     Log(LastException.Message)
   End Try
ma quante righe sono???? ma quanto tempo ci vuole????
ora succede che accanto al titolo della APP ,in alto a SX, compare la scritta (non risponde)...il refresh non avviene ,se non con l'utilizzo di un TIMER... ed il tutto sembra INCHIODATO! ok, giusto! il tutto poi va a buon fine... ma vorrei risolvere MOSTRANDO una APP veloce.
quindi pensavo di INCARICARE un SERVIZIO oppure CALLSUB CALLSUBDELAY per far eseguire questi aggiornamenti.
da dove comincio? Ricomincio da tre. (M. Troisi)
 

LucaMs

Expert
Licensed User
Longtime User
Se non ho capito male, leggi una serie di query da eseguire poi, giustamente, in una transaction.

Non vedo come mai sia tanto lenta, 300 query non sono molte. Quanto tempo impiegano?

Comunque, puoi spostare tutto in un modulo di servizio e in questo effettuare una chiamata ad una Activity quando l'operazione è completata, usando CallSubDelayed per avvisare ED AVVIARE l'Activity (questa è una cosa che non avevo scritto: usando questo metodo, l'Activitiy verrà avviata, se non è già attiva).

Cioè metti in un'Activity:

Sub DatiPronti
' quindi fai qualcosa
End Sub

e la chiami dal modulo di servizio, al termine della transazione:

CallSubDelayed(NomeActivity, "DatiPronti")
 

giannimaione

Well-Known Member
Licensed User
Longtime User
.... lentissimo... ho provato con diversi pc e con diverse versioni di win ma il risultato non cambia di molto.
non contento ho fatto delle prove con B4A, con un dispositvo poco performante... risultato??? velocissimo...

a questo punto ho generato i dati con un numero di righe/query inferiori...
quindi molti piu files ma con meno righe/query...
verificato!!! va molto meglio!!!! ho aggirato il problema, ma non capisco questa lentezza.
tra l'altro, sono rimasto meravigliato dalla velocità della SELECT e il successivo "riepimento" di una TABLEVIEW.... circa 7000 records nell'ordine di 1 , 2 secondi.

in ogni caso grazie per il tuo aiuto.
 

LordZenzo

Well-Known Member
Licensed User
Longtime User
per le routine lente, per far vedere che procede potresti provare ad usare un DoEvents e un "contatore" o "barra" che da almeno visivamente l'idea che funziona, evitando la scritta "non risponde", basta che non permetti al utente di far qualsiasi cosa che possa interferire con la app stessa
 

giannimaione

Well-Known Member
Licensed User
Longtime User
in B4A SQLite,
in B4J la libreria jSQL e poi in Region Project Attributes #AdditionalJar: sqlite-jdbc-3.7.2

in B4J non esiste DoEvents
 

LucaMs

Expert
Licensed User
Longtime User
Quindi stesso tipo, sempre SQLite.

Beh, non si può accettare che sul PC sia più lento che su un dispositivo mobile.

Ergo... ce dovemo pensa' :p

Per oggi ho fuso a sufficienza :(

Se vuoi allegare qui o inviarmi tramite email parte del progetto, prometto che gli darò un'occhiata :)
 

giannimaione

Well-Known Member
Licensed User
Longtime User
va meglio... ma mica tanto!
in pratica modificando
B4X:
Main.sqlt.ExecNonQuery(line)
con
B4X:
Main.sqlt.AddNonQueryToBatch(line,Null): 'qui è velocissimoooooooo!
e aggiungendo alla fine
B4X:
Dim now As Long
now = DateTime.Now
Log(DateTime.Time(now)):'visulizza orario di inizio "update"
sql1.ExecNonQueryBatch("SQL"):' come se eseguisse TUTTE le query in background o servizio
...
...
...

Sub SQL_NonQueryComplete (Success As Boolean)
If Success=True Then   
   Dim now As Long
   now=DateTime.Now
   Log(DateTime.Time(now)):'visulizza orario di fine "update"
Else
     Log("ERRORE")
     Log(LastException)
   End If
End Sub
il tempo necessario rimane praticamente lo stesso circa 5 (cinque) minuti....
di contro l'APP (le altre form presenti) rispondono MOLTO lentamente...
a questo punto forse è il caso di visulizzare una LABEL GIGANTE 'ATTENDERE PREGO... fai una pausa caffè'
 

LucaMs

Expert
Licensed User
Longtime User
Hai usato questo modo (dalla documentazione)?:

B4X:
AddNonQueryToBatch (Statement As String, Args As List)
Adds a non-query statement to the batch of statements.
The statements are (asynchronously) executed when you call ExecNonQueryBatch.
Args parameter can be Null if it is not needed.

Example:

For i = 1 To 10000
    sql1.AddNonQueryToBatch("INSERT INTO table1 VALUES (?)", Array As Object(Rnd(0, 100000)))
Next
sql1.ExecNonQueryBatch("SQL")
...
Sub SQL_NonQueryComplete (Success As Boolean)
  Log("NonQuery: " & Success)
  If Success = False Then Log(LastException)
End Sub
 

giannimaione

Well-Known Member
Licensed User
Longtime User
Se non sbaglio, potresti intanto leggere tutte le query dal file di testo usando:
Dim lstQueries As List = File.ReadList(...)
che sudata!!!!
il problema è causato da una serie di istruzioni "delete from ...... where ....." .... incredibile
ho filtrato il tutto SCARTANDO queste query (delete) ... ed ora bastano pochi secondi!!!!
 

FabioRome

Member
Licensed User
Longtime User
CallSub chiama una funzione e si mette in attesa fino a che non finisca
CallSubDelayed chiama una funzione ed esegue subito il restante codice senza aspettare che la funzione chiamata finisca
 
Top