Italian [B4X] [B4XPages] Tre pagine [Three pages + Network + AsyncStreams + B4XSerializator]

Solution
@Elric
Prova questo.
Sono partito dall'esempio originale di Erel e da lì ho tagliato e cucito.
Ora ci sono 3 pagine:
- la prima dove ti connetti
- la seconda con Nome ed Età
- la terza con il Canvas dove disegnare
Nelle pagine Nome ed Età e Canvas è presente il button per inviare i dati.
Ogni volta viene inviato tutto, sia l'immagine del Canvas che Nome ed Età.
Con un pò di lavoro in più si potrebbe inviare anche solo il contenuto della singola pagina.
Tutto ciò che riguarda la comunicazione è nella MainPage e quindi le altre pagine inoltrano le loro richieste lì, senza duplicare nulla in giro.
Al netto degli errori e degli inevitabili miglioramenti possibili pare funzionare.
Spero che questo fosse ciò che stavi cercando di...

Sagenut

Expert
Licensed User
Longtime User
L'esempio che hai postato dovrebbe già darti quel che ti serve.
Una volta create le 3 (o più) pagine tratterai ognuna come fosse una vecchia Activity.
Quindi dovrai creare 3 layout, uno per ogni pagina, con quello che vuoi metterci.
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
Eventualmente spiega cosa non ti è chiaro così vediamo di aiutarti.
Non so se domani avrò tempo per fare un esempio.
Ma se riesco ci provo.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Grazie!

Se ho capito bene, si è obbligati a replicare lo stesso gruppo di sub per la connessione (ListenForConnection, Astream etc.)? Se così è (lo avevo pensato ma lo avevo scartato):
  • come faccio a connettermi in B4XMainPage e tenere la connessione attiva in B4XPage2 se devo inizializzare una nuova variabile server etc?
  • Ho provato a tenere il gruppo di sub per la connessione in B4XMainPage con variabile server impostata come public ma richiamandola da B4XPage2 mi risulta vuota. Quindi questo approccio è sbagliato?
  • Se devo replicare il gruppo di sub per la connessione, questo vuol dire che non le posso mettere in una classe a sé stante? Cosa che mi suona strano, perché se voglio avere più istanze, magari su due porte diverse, non lo posso fare ma questo è un dubbio che non sorge dalla pratica...
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
@Elric
Io direi di iniziare postando quanto hai fatto finora.
Sarà più facile correggere da quei che già hai che magari necessita solo di piccole modifiche.
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
Sto buttando un occhio al tuo progetto.
La connessione la effettua la B4XMainPage, e una volta stabilita non dovrebbe esserci bisogno di farla nelle altre pagine.
La cosa buona delle B4XPages è che restano sempre tutte attive e continuano a lavorare.
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
Non credo di poter provare il progetto perchè non saprei a cosa collegarmi.
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
Nella B4XMainPage ho forzato qualcosa in
B4X:
cConnect.strMyIP = "SONO CONNESSO"
e quel "SONO CONNESSO" lo ritrovo anche nella Pag2.
Quindi pare funzionare.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Sto buttando un occhio al tuo progetto.
Grazie!
La connessione la effettua la B4XMainPage, e una volta stabilita non dovrebbe esserci bisogno di farla nelle altre pagine.
La cosa buona delle B4XPages è che restano sempre tutte attive e continuano a lavorare.
Si, ho replicato le view in pag2 solo per test.

Il problema è che non trasmette i dati. Premendo "Send" da un dispositivo (es. Computer) dovrebbe trasmettere all'altro dispositivo (smatphone) ma non lo fa...
 
Upvote 0

Sagenut

Expert
Licensed User
Longtime User
Quando avrò più tempo lo proverò meglio.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Forse ho risolto.

Pare, ogni pagina pare debba avere una sua sub ListenForConnections che punti alle variabili della classe dedicata alla connessione (che io ho definito cConnect as clsConnect) inizializzata nella B4XMainPage:
B4X:
Private Sub ListenForConnections
    Do While True
        B4XPages.MainPage.cConnect.server.Listen
        Wait For Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        If Successful Then
            B4XPages.MainPage.cConnect.CloseExistingConnection
            B4XPages.MainPage.cConnect.client = NewSocket
            B4XPages.MainPage.cConnect.astream.InitializePrefix(B4XPages.MainPage.cConnect.client.InputStream, False, B4XPages.MainPage.cConnect.client.OutputStream, "astream")
            B4XPages.MainPage.cConnect.ynConnected = True
            B4XPages.MainPage.cConnect.UpdateState(B4XPages.MainPage.cConnect.ynConnected)
        End If
    Loop
End Sub

Nel tutorial B4XSerializator, antecedente alle B4XPages, mi pare che chiarisca fin dall'inizio che alcune sub devono rimanere nel main.

E così, se il "gruppo Astream" (AStream_NewData, AStream_Terminated, AStream_Error e SendData) lo metto in una classe, la sub SendData non funziona, mentre funziona se rimane nella B4XMainPage.

Questo fa sì che la classe dedicata per la connessione si riduca di molto, ma sempre utile.

Faccio qualche altro test e, se mi pare che tutto fili, allegherò qui il progetto.

Grazie!
 
Upvote 0

Elric

Well-Known Member
Licensed User
Allego progetto anche se non funziona del tutto.

Sebbene riesca a far inviare dal client al server dei dati mantenendo la connessione tra le pagine, non riesco a ricevere dal server.

Ad esempio, a "pag3" il client prende due numeri e li spedisce al server che li somma e restituisce (dovrebbe restituire) il risultato.

Il server, in effetti, riceve e fa la somma ed invia ma il client non riceve il risultato.

Con client in B4J e server in B4A, il client in B4J restituisce questo errore:
B4X:
java.lang.RuntimeException: java.lang.Exception: Sub astream_newdata was not found.
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA$2.run(BA.java:250)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.Exception: Sub astream_newdata was not found.
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:118)
    ... 9 more

Con client in B4A e server in B4J, il client in B4A non riceve senza restituire alcun errore.
 

Attachments

  • NetworkExampleThreeB4XPages.zip
    199.7 KB · Views: 20
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
C'è un po' di casino.

Innanzitutto, nella classe clsConnect dichiari DUE oggetti Socket, mentre dovrebbe essere uno solo.

Poi i dati il client dovrebbe riceverli nella B4XMainPage e basta, nella AStream_NewData. Da qui li girerai alla pagina opportuna, il che significa che i dati stessi dovrebbero contenere indicazioni al client circa quale pagina sarà coinvolta.

Non serve la classe clsConnect se metti il suo contenuto nella B4XMainPage.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Innanzitutto, nella classe clsConnect dichiari DUE oggetti Socket, mentre dovrebbe essere uno solo.
Se ti riferisci a:
B4X:
    Public client As Socket
    Public server As ServerSocket
Non mi sono inventato niente, sono come da esempio di Erel. L'unica cosa che mi sono inventato è metterli dentro una classe... cosa che ho scoperto essere abbastanza inutile, concordo.

Poi i dati il client dovrebbe riceverli nella B4XMainPage e basta, nella AStream_NewData. Da qui li girerai alla pagina opportuna, il che significa che i dati stessi dovrebbero contenere indicazioni al client circa quale pagina sarà coinvolta.
Ma è quello che fa!
In clsConnect ci sono solo ConnectToServer, CloseExistingConnection e UpdateState. Il gruppo Astream è dentro B4XMainPage.

Non serve la classe clsConnect se metti il suo contenuto nella B4XMainPage.
Concordo ma credo che il mio problema resti.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Se ti riferisci a:
No, quelli sono due oggetti diversi, Socket per il client, ServerSocket per il server, in quanto il progetto può svolgere entrambe le funzioni (a scelta, alternativamente).
Mi riferisco, invece, a:
1714727249878.png


In quella classe hai dichiarato una variabile di tipo Socket nella Class_Globals e un'altra nella Sub ConnectToServer (e questa seconda è un errore).

Come vedi, hai anche 3 punti, in 3 pagine diverse, in cui attendi l'evento NewConnection, mentre dovrebbe essercene uno solo, nella classe clsConnect o, se da questa sposti tutto nella B4XMainPage, in quest'ultima.
[Questa serve quando il progetto funge da server ed un ennesimo client si connette]
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Ma è quello che fa!
In clsConnect ci sono solo ConnectToServer, CloseExistingConnection e UpdateState. Il gruppo Astream è dentro B4XMainPage.
AStream_NewData dovrebbe stare nello stesso "luogo" di quelle, ovvero nella clsConnect o, se ripeto sposti tutto nella B4XMainPage, in questa.
Quello che intendevo è che:
sia che tu sposti tutto il codice dalla clsConnect alla B4XMainPage (consigliato), sia che lo lasci nella classe, di cui avrai un'unica istanza (diciamo variabile) nella B4XMainPage, quando dal client arrivano dati chiamerai qualche sub di qualche pagina a cui passarli e per sapere a quale pagina, dipenderà dai dati ricevuti.

Cioè, metti che tu abbia una pagina Bingo e una Impiccato (due giochi), il client dovrà inviare un dato che faccia capire al server a quale dei due giochi voglia passare il resto dei dati. Questo perché ci sarà un solo punto in tutto il progetto in cui arriveranno i dati da un client (Sub ASTream_NewData).
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Comunque, a meno che a te non serva un progetto fatto proprio come quello dell'esempio, ovvero che possa fungere sia da server che da client, in base alla scelta dell'utente, io creerei due progetti ben distinti, un server ed un client.
 
Upvote 0
Top