Italian B4XPages, B4XView. Cosa mi offrono rispetto alle Activity?

Sabotto

Well-Known Member
Licensed User
Buonasera a tutti. Dopo neanche un mesetto di apprendimento e prove con B4A (e due app create, a me utilissime, che mi evitano di accendere il Pc ogni volta che devo usarle, le avevo infatti create in VB.NET), sto cercando di approfondire questo bellissimo mondo. Le B4XPages e relative B4XView.
Vorrei capire una cosa: il vantaggio principale maggiore di usare le 'pages' al posto delle 'Activity' è il "cross platform"?, uello che un'app creata per Android, puo facilmente essere trasformata per IOS o che altro?
Ho visto il tutorial di Erel, ma non sono bravissimo con l'inglese e mi perdo un po. Se uno 'italiano' mi da giusto due dritte capisco molto di piu. Tutorial in italiano non ne ho trovati. Ho cercato male?
Insomma non ho capito ancora che vantaggi avrei praticamente, ma ho pensato che se devo approcciare ad un altra tecnica è meglio farlo ora e non quando sarò radicato nelle Activity. Qui sul forum ci sono LucaMs, StarDust, Sagenut, Ufg, SirJo66, tanto per citarne solo alcuni molto presenti, con tanta esperienza da cui sto imparando molto solo leggendo i relativi post di risposta.
Qualsiasi link è ben accetto. Buona serata a tutti
 
Last edited:

udg

Expert
Licensed User
Longtime User
A questo link trovi il riassunto dei vantaggi delle B4XPages:

Al di là della compatibilità tra piattaforme, il principale vantaggio è che le pagine non sottostanno a quello che era il delicato ciclo di vita delle activity. Ora è un po' come avere in mano un libro (il processo che sottende alla tua app) e poter liberamente passare da una pagina all'altra perchè tutte coesistono. Finchè hai il libro in mano (ovvero finchè il processo non viene distrutto) le pagine ed il loro contenuto sono sempre disponibili.
Per le activity era diverso. Ognuna aveva il suo ciclo di vita, poteva essere distrutta e ricreata in ogni momento. Un po'come avere fogli sparsi da prendere uno alla volta (anche se tutte appartenevano al solito processo-app).

ps: è una semplificazione, ma credo renda l'idea
 
Last edited:

Sagenut

Expert
Licensed User
Longtime User
Le B4XView sono invece un potenziamento rispetto alle normali View.
Oltre a consentirti il cross platform ti forniscono ulteriori metodi altrimenti non presenti nelle View native.
In qualunque momento puoi anche trasformare una View in B4XView e viceversa da codice.
 

LucaMs

Expert
Licensed User
Longtime User
Ho visto il tutorial di Erel, ma non sono bravissimo con l'inglese e mi perdo un po'
Insomma non ho capito ancora che vantaggi avrei praticamente


Traduzione di [B4X] [B4XPages] What exactly does it solve? - [B4X] [B4XPages] Cosa risolve esattamente?


Come spiegato nel tutorial B4XPages, gli scopi delle B4XPages sono due:

1 - fornire uno strato (livello superiore) che sia multipiattaforma;
2 - semplificare lo sviluppo di app B4A.

I vantaggi dello "strato multipiattaforma" sono evidenti: B4XPages nasconde molte delle differenze tra le Activity B4A, le Page B4i e i moduli B4J. Con B4XPages è banale creare una "app a pagine multiple" in cui tutto il codice sia condiviso (tranne il codice del modello che viene semplicemente incollato nel modulo principale).
Con le Activity, richiederebbe la creazione di un'Activity + classe condivisa + pagina / modulo per ogni pagina. Parecchio lavoro.

Le tre cose più importanti riguardanti le classi B4XPage sono:

1 - Le classi B4XPages sono normali classi al 100%. Non hanno un ciclo di vita speciale e puoi usarle come vuoi. Ci sono alcuni eventi specifici B4XPages ma non influenzano lo stato della classe stessa. Questo non succede con le Activity.

2 - Le classi B4XPages non vengono mai messe in pausa. Non succede alcunché di speciale quando una pagina non è più visibile o quando l'app passa in background. Ovviamente il sistema operativo continuerà a poter chiudere l'intero processo (l'app) quando l'app stesse in background (a lungo e in caso di necessità da parte del S.O., come scarsità di memoria, ad esempio).

3 - Le classi B4XPages non vengono mai distrutte (singolarmente). Le variabili globali della classe e lo stato delle View non verranno mai resettati (fintanto che il processo sopravvive).

I 3 punti sopra rendono molte cose semplici. Alcune sono:
  1. Gli eventi non vengono mai persi né accodati.
  2. I comandi Sleep non vengono mai annullati. Ad esempio, non è più necessario riavviare le animazioni in Activity_Resume.
  3. Lo stato dell'interfaccia utente viene mantenuto per tutta la durata del processo.
  4. Nella maggior parte dei casi non è necessario utilizzare il servizio Starter.
  5. Possiamo chiamare direttamente metodi pubblici di altre pagine. Non è necessario utilizzare CallSub o CallSubDelayed.
  6. Possiamo accedere direttamente alle variabili globali pubbliche di altre pagine.
  7. Possiamo accedere direttamente e manipolare le View di altre pagine.
  8. Possiamo decidere se creare i layout immediatamente quando viene creata una pagina (B4XPages.AddPageAndCreate).
  9. Possiamo spostare le View tra le pagine.
  10. Non c'è bisogno di preoccuparsi dei casi in cui CallSubDelayed avvii l'Activity precedente in modo imprevisto (di solito accade con HttpJobs).
  11. Possiamo usare la stessa classe di pagina per creare molte istanze di pagina.
  12. Un unico posto con un unico e semplice comportamento per le variabili globali.
  13. Non c'è bisogno di pensare a cosa dovrebbe essere inizializzato quando FirstTime sia True e cosa, invece, debba essere inizializzato ogni volta.
  14. Non è necessario gestire i casi in cui venga avviata per prima un'Activity che non sia la Main.
  15. Migliore controllo sullo stack (pila) delle pagine poiché è implementato nel codice B4X.
  16. Gestione automatica del "indicatore di salita" (pagina precedente). Non è necessario utilizzare la libreria AppCompat per questo.
  17. Modo molto semplice e flessibile per gestire il Back Key - tasto indietro.
  18. Eventi Background e Foreground che vengono generati in tutte le pagine quando l'app vada in background e in foreground (non così semplice da ottenere con le Activity e necessario in molti casi).
  19. Nessuna distinzione tra classi contenenti il "contesto di attività" (context) che devono essere dichiarate in Globals ed altre classi che possono essere dichiarate in Process_Global.
  20. Non è necessario suddividere l'implementazione tra un livello dell'interfaccia utente senza stato e un livello non dell'interfaccia utente con stato.

Detto questo, nessuno è costretto a passare a B4XPages. Tutto continuerà a funzionare esattamente come prima. È troppo presto per affrettarsi e convertire grandi progetti già funzionanti.
 
Last edited:

Sabotto

Well-Known Member
Licensed User
Perfetto. Non mi resta che provare...

ehm...
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
   
End Sub

la Created sarebb la "Load" di Vb e la Create di B4A, giusto?
Ma root e root1?

Nel post che ho cominciato a leggere di Erel qui non mi pare che lo spieghi...

Grazie a tutti comunque. Per specifici intoppi aprirò appositi post
 

LucaMs

Expert
Licensed User
Longtime User
la Created sarebb la "Load" di Vb e la Create di B4A, giusto?
Così "completiamo" questo thread...

Traduzione (non del tutto letterale, come la precedente, del resto) anche di B4XPages Events:

Eventi B4XPages

  • B4XPage_Created: chiamato (=routine eseguita) una sola volta quando la pagina viene creata. Ciò accadrà prima che la pagina diventi visibile o dopo una chiamata a B4XPages.AddPageAndCreate.
  • B4XPage_Appear - Chiamato ogni volta che la pagina diventa visibile.
  • B4XPage_Disappear - Chiamato ogni volta che una pagina visibile scompare.
  • B4XPage_Background: chiamato quando l'app viene messa in background. Questo evento verrà generato in tutte le pagine che implementano questa routine-evento, non solo nell'evento della pagina principale. Questo è un buon posto per salvare tutto ciò che deve essere salvato poiché il processo potrebbe essere interrotto in seguito. Notare che in B4J viene sollevato quando l'ultima pagina viene chiusa.
  • B4XPage_Foreground: chiamato quando l'app è stata portata in primo piano.
  • B4XPage_Resize (B4J / B4i) - Chiamato quando la pagina viene ridimensionata.
  • B4XPage_CloseRequest (B4J / B4A) - In B4A viene chiamato quando l'utente fa clic sul tasto Back o sul "indicatore su". In B4J viene chiamato quando l'utente fa clic sul pulsante di chiusura. Vedi il post # 4 per maggiori informazioni.
  • B4XPage_MenuClick - Chiamato quando si fa clic su una voce di menu o su BarButton in B4i. Vedi il post # 5 per maggiori informazioni.
  • B4XPage_KeyboardStateChanged (B4i): chiamato quando lo stato della tastiera cambia.
  • B4XPage_IconifiedChanged (B4J) - Chiamato quando una pagina viene ridotta a icona o ripristinata.
  • B4XPage_PermissionResult (B4A) - Generato dopo una chiamata a rp.CheckAndRequest.
 

LucaMs

Expert
Licensed User
Longtime User
Ma root e root1?
Quando la pagina viene creata, riceve Root (che è un Panel in B4A, un Pane in B4J, e non so bene cosa in B4i ma comunque analogo) ma non potresti usarlo nel resto del codice sorgente perché non sarebbe accessibile; per questo viene usato un riferimento a quella Root, creando una variabile globale Root1.

In pratica, Root e Root1 "sono" la stessa cosa (puntano allo stesso "Panel"), che è il Panel di base nel quale caricare il layout.

Sono dichiarati come B4XView proprio per consentire la programmazione multi-piattaforma. Come tutte le B4XView, in qualunque momento puoi convertirle nella View originale, nel caso in cui fosse necessario (magari questo lo scriverò meglio in seguito).
 

Sabotto

Well-Known Member
Licensed User
Non ho ben capito una cosa.
Se dichiaro
B4X:
Private Label1 as label
lui sa che è una label e mi propone metodi ed eventi di una label
Ma se la dichiaro
B4X:
Private Label2 as B4XView
,
Se scrivo Label2. (punto finale) intellisense mi mostra tutti i metodi anche di altre view (tipo checked ad esempio) ma in realtà lui da designer sa gia che è un B4XView ma di tipo Label, e mi dà giustamente errore se scrivo Label2.Checked. Questo vuol dire che devo "starci attento io" per cosi dire. Mi sarei aspettato quindi non un unico tipo B4XView ma B4XViewLabel, B4XViewButton, ecc.
Non so se sono riuscito a spiegarmi
 

LucaMs

Expert
Licensed User
Longtime User
Non so se sono riuscito a spiegarmi
Perfettamente.

In effetti non sarebbe male avere B4XViewLabel (o, abbreviato, bxvLabel) etc.

B4XView è una sorta di involucro che può contenere una qualunque View, sia quelle B4A che le B4I e B4J, questo è il vantaggio.
Alcune proprietà o metodi elencate dall'help contestuale, quando digiti il nome della variabile e poi il punto, funzioneranno effettivamente solo in base al "contenuto" effettivo della B4XView, come hai scritto; l'help stesso lo specifica, ti dice per quale tipo di view "nativa" una certa proprietà/metodo sia valida.

In alcuni casi non sarà possibile usare proprietà e metodi di una B4XView. Ad esempio, potrei dichiarare una bxvMyWebView As B4XView ma nessuno o quasi dei membri (parola unica per proprietà e metodi) di B4XView potranno applicarsi alla WebView che conterrà. In questi casi, dovrai usare una variabile temporanea, più o meno in questo modo:
B4X:
' Userò spesso questa View come B4XView
Private bxvMyWebView As B4XView


' Qui devo usare un membro della WebView originale...
#If B4A
    Dim wv As WebView = bxvMyWebView
    wv.MembroOriginale
#Else If B4I
    '....

Le #If B4A ... a volte sono necessarie perché la View originale "contenuta" nella B4XView è diversa nei 3 diversi ambienti.
 

LucaMs

Expert
Licensed User
Longtime User
Sembra che i vantaggi nell'usare le B4XView siano pochi, ma non è così.

Allego un progetto B4XPages, moooooolto semplice, in pratica contiene soltanto una "input box", una "casella per immissione testo".

La pagina principale, B4XMainPage, che è unica per tutti gli ambienti (B4A, B4i, B4J) contiene solo:

Dim tfName As B4XView

tfName.Text = "Ciao"

mentre i layout sono 3, uno per ambiente (lo crei con B4J, ad esempio, e poi copi e incolli le view negli altri Designer. In B4J ho creato la tfName come TextField; poi, copiandola nel Designer di B4A, questo l'ha cambiata automaticamente in EditText).

Quindi, il codice sorgente è comune a tutti e 3 gli ambienti, non devi scrivere 3 diverse B4XMainPage, una per ogni piattaforma.
 

Attachments

  • xpB4XViewTest.zip
    14.2 KB · Views: 319

Sabotto

Well-Known Member
Licensed User
Ma una variabile dichiarata Public in Page1, come la richiamo in Page2?
E a cosa serve la routine Initialize?

B4X:
'in B4XMainPage
Sub Class_Globals
    Public Page1_Glo1 As Int = 20
End Sub

Public Sub Initialize
    
    'Cosa ci va qui?
    
End Sub

'In un altra page
Log(B4XMainPage.Page1_Glo1 )' dà errore. Come va scritta?
 

LucaMs

Expert
Licensed User
Longtime User
Perfettamente.

In effetti non sarebbe male avere B4XViewLabel (o, abbreviato, bxvLabel) etc.

B4XView è una sorta di involucro che può contenere una qualunque View, sia quelle B4A che le B4I e B4J, questo è il vantaggio.
Alcune proprietà o metodi elencate dall'help contestuale, quando digiti il nome della variabile e poi il punto, funzioneranno effettivamente solo in base al "contenuto" effettivo della B4XView, come hai scritto; l'help stesso lo specifica, ti dice per quale tipo di view "nativa" una certa proprietà/metodo sia valida.

In alcuni casi non sarà possibile usare proprietà e metodi di una B4XView. Ad esempio, potrei dichiarare una bxvMyWebView As B4XView ma nessuno o quasi dei membri (parola unica per proprietà e metodi) di B4XView potranno applicarsi alla WebView che conterrà. In questi casi, dovrai usare una variabile temporanea, più o meno in questo modo:
B4X:
' Userò spesso questa View come B4XView
Private bxvMyWebView As B4XView


' Qui devo usare un membro della WebView originale...
#If B4A
    Dim wv As WebView = bxvMyWebView
    wv.MembroOriginale
#Else If B4I
    '....

Le #If B4A ... a volte sono necessarie perché la View originale "contenuta" nella B4XView è diversa nei 3 diversi ambienti.
"Oggi" (da quando è stato aggiunto il "casting in linea") questo è ancora più facile.
Se sai che una variabile BX di tipo B4XView "contiene" una Label, si potrà scrivere:
B4X:
BX.As(Label).[qui l'editor elencherà tutti e solo i membri delle Label]
 

LucaMs

Expert
Licensed User
Longtime User
Ma una variabile dichiarata Public in Page1, come la richiamo in Page2?
E a cosa serve la routine Initialize?

B4X:
'in B4XMainPage
Sub Class_Globals
    Public Page1_Glo1 As Int = 20
End Sub
Ti rispondo con "leggerissimo" ritardo ? :( (Cosa vuoi che siano 3 anni in confronto agli 8 o 9 che ho in mente un'app che non ho ancora realizzato/pubbllicato?!).

Premesso che non mi piacciono molto le variabili pubbliche, preferisco di gran lunga creare una proprietà dell'oggetto per modificare, da fuori, il valore di una variabile privata, globale solo a livello di classe...

la "richiami" esattamente come con qualunque oggetto, perché quello che deve essere chiaro è che una B4XPage è una classe della quale si creano oggetti (istanze della classe).

Quando scrivi:

Label1.Text = "Ciao"

hai "richiamato" un membro della classe Label ma più precisamente dell'oggetto Label1 che è un'istanza della classe Label (classe a noi nascosta, fa parte di B4A, o meglio di Android).

Stessa cosa con le classi B4XPage. Se ad esempio hai una classe (B4XPage) Catalogo, in qualche punto del progetto avrai una variabile-oggetto di tipo Catalogo. Avrai qualcosa tipo:

Public CatalogoXXX As Catalogo
CatalogoXXX.Initialize
'Solo in quanto è una B4XPage, l'aggiungerai alla "lista" di pagine,

Poi "richiamerai" (utilizzerai) i suoi metodi, le sue proprietà e le sue variabili pubbliche come fai con qualunque altro oggetto, quindi come la Label1 d'esempio sopra.

CatalogoXXX.VariabilePubblica = 100

Ma dipende da dove hai dichiarato (e inizializzato) CatalogoXXX. Se io l'avessi dichiarata nel mio modulo di codice chiamato modAffariMiei, dovrei scrivere:

modAffariMiei.CatalogoXXX.Esegui ("Esegui" potrebbe essere un metodo, una Sub pubblica della classe CatalogoXXX)



'In un altra page Log(B4XMainPage.Page1_Glo1 )' dà errore. Come va scritta?
Ti dà errore perché B4XMainPage è una classe, non un'istanza della classe B4XMainPage (non un oggetto),
Esiste un oggetto di tipo B4XMainPage di nome MainPage che sta in B4XPages.GetManager.MainPage, quindi dovresti scrivere:

B4XPages.GetManager.MainPage.Page1_Glo1 = 100



Public Sub Initialize 'Cosa ci va qui? End Sub
Semplicemente ci vanno tutte le inizializzazioni delle variabili (anche oggetto) che userai.
Anche se tutti hanno il "vizio" di inizializzare gli oggetti pagina nella B4XPage_Create, sarebbe il posto più corretto anche per fare questo.
 
Last edited:
Top