Android Tutorial AsyncStreamsObject - Send and receive objects instead of bytes

AsyncStreamsObject is a small framework built over AsyncStreams.

Instead of sending and receiving bytes, AsyncStreamsObject allows you to send and receive objects. This makes it much simpler to communicate with other devices.

AsyncStreamsObject uses the WriteStream method of AsyncStreams. This method was introduced in RandomAccessFile v1.5.

You can use AsyncStreamsObject when you implement both sides of the connection.

SS-2013-06-26_10.32.47.png


Supported objects

WriteObject supports: Lists, Arrays, Maps, Strings, primitive types and user defined types.

WriteBitmap allows you to send bitmaps.

WriteFile allows you to send any file.

All the three write methods expect a key (string) and a value (the actual object).

The NewObject event is raised when an object is received. You should use the key to decide how to handle the object. This code is taken from the attached example:
B4X:
Sub astreamO_NewObject(Key As String, Value As Object)
   Select Key
      Case "form"
         Dim m As Map = Value 'Value is a Map
         txtFirst.Text = m.Get("first")
         txtLast.Text = m.Get("last")
         txtAnimal.Text = m.Get("animal")
      Case "simple value"
         Dim number As Int = Value
         ToastMessageShow("Received lucky number: " & number, False)
      Case "image"
         Dim bmp As Bitmap = Value
         Dim r As Rect
         r.Initialize(0, 0, Panel1.Width, Panel1.Height)
         cvs.DrawBitmap(bmp, Null, r)
         Panel1.Invalidate
      Case "file"
         Dim fileName As String = value
         Log("Received file. File size: " & File.Size(astreamO.TempFolder, fileName))
   End Select
End Sub

The ObjectSent event is raised after a value was successfully sent.
B4X:
Sub astreamO_ObjectSent (Key As String)
   Log("Object sent: " & Key)
End Sub

Initializing AsyncStreamsObject

Two steps are required. First you should call AsyncStreamsObject.Initialize and pass the target module and event name:
B4X:
astreamO.Initialize(Me, "astreamO")

Once there is a connection you should call AsyncStreamsObject.Start:
B4X:
Sub StartAstream(s As Socket)
   astreamO.Start(s.InputStream, s.OutputStream)
   SetUIState
End Sub
Note that you can use any type of connection that provides an input stream and output stream.

The Terminated event is raised when the connection is closed.

The attached example connects two devices over the local network. You need to set the IP address of one of the devices and press on the Connect button. Once connect you can send data between the devices.

AsyncStreamsObject class is included in the attached example.
 

Attachments

  • AsyncStreamsObject.zip
    10.5 KB · Views: 3,976
Last edited:

scrat

Active Member
Licensed User
Longtime User
Hi,

I try to use asyncstreamsobject to send file from B4j (PC) to B4a.
I have no problem when i send just a few files (1/10 files).
Now I have to send 200 litle files (50ko/100ko).
I use a for/next loop and between 50/100 files i encountered this error :
B4X:
java.lang.NegativeArraySizeException: -1991225786
   at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.readHelper(RandomAccessFile.java:377)
   at anywheresoftware.b4a.randomaccessfile.RandomAccessFile.ReadObject(RandomAccessFile.java:364)
   at fr.test.example.asyncstreamsobject._astream_newstream(asyncstreamsobject.java:113)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
   at anywheresoftware.b4a.BA$3.run(BA.java:320)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Any idea ?

Thanks
 

scrat

Active Member
Licensed User
Longtime User
Thank' s Erel

I change the code by sending one file after another and that's OK now
 

Francisco Picado

Member
Licensed User
Longtime User
hi, every one. i came at this post because i was searching for a way to sync files between 2 devices though bluetooth, what call my attention is that this code can send objects like pictures, and that i what i need in my app, but my question is : is the only way this example work is only by wifi? or can i configured to work by bluetooth?. this is because the 2 devices won't be able to connect to a wifi network.? thanks in advance.
 

koaunglay

Member
Licensed User
Longtime User
AsyncStreamsObject is a small framework built over AsyncStreams.

Instead of sending and receiving bytes, AsyncStreamsObject allows you to send and receive objects. This makes it much simpler to communicate with other devices.

AsyncStreamsObject uses the WriteStream method of AsyncStreams. This method was introduced in RandomAccessFile v1.5.

You can use AsyncStreamsObject when you implement both sides of the connection.

SS-2013-06-26_10.32.47.png


Supported objects

WriteObject supports: Lists, Arrays, Maps, Strings, primitive types and user defined types.

WriteBitmap allows you to send bitmaps.

WriteFile allows you to send any file.

All the three write methods expect a key (string) and a value (the actual object).

The NewObject event is raised when an object is received. You should use the key to decide how to handle the object. This code is taken from the attached example:
B4X:
Sub astreamO_NewObject(Key As String, Value As Object)
   Select Key
      Case "form"
         Dim m As Map = Value 'Value is a Map
         txtFirst.Text = m.Get("first")
         txtLast.Text = m.Get("last")
         txtAnimal.Text = m.Get("animal")
      Case "simple value"
         Dim number As Int = Value
         ToastMessageShow("Received lucky number: " & number, False)
      Case "image"
         Dim bmp As Bitmap = Value
         Dim r As Rect
         r.Initialize(0, 0, Panel1.Width, Panel1.Height)
         cvs.DrawBitmap(bmp, Null, r)
         Panel1.Invalidate
      Case "file"
         Dim fileName As String = value
         Log("Received file. File size: " & File.Size(astreamO.TempFolder, fileName))
   End Select
End Sub

The ObjectSent event is raised after a value was successfully sent.
B4X:
Sub astreamO_ObjectSent (Key As String)
   Log("Object sent: " & Key)
End Sub

Initializing AsyncStreamsObject

Two steps are required. First you should call AsyncStreamsObject.Initialize and pass the target module and event name:
B4X:
astreamO.Initialize(Me, "astreamO")

Once there is a connection you should call AsyncStreamsObject.Start:
B4X:
Sub StartAstream(s As Socket)
   astreamO.Start(s.InputStream, s.OutputStream)
   SetUIState
End Sub
Note that you can use any type of connection that provides an input stream and output stream.

The Terminated event is raised when the connection is closed.

The attached example connects two devices over the local network. You need to set the IP address of one of the devices and press on the Connect button. Once connect you can send data between the devices.

AsyncStreamsObject class is included in the attached example.
Can it use Android device to device over Internet. I mean chat apk like whatapp, viber.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
This question is not really related to AsyncStreamsObject. Generally speaking it is not possible to connect two devices over the internet directly. You will need a server that will receive the messages from one device and will send them to the other devices.

See this example: https://www.b4x.com/android/forum/threads/40272/#content
 

TheMightySwe

Active Member
Licensed User
Longtime User
Hi,

I'm trying to send a Map through AsyncStreamsObject, and i get this error When I try to do this.

B4X:
Sub ASO_Client_NewObject(Key As String, Value As Object)

    If Debug = True Then Log("ASO_Client_NewObject(Key=" & Key & ")")
    If Debug = True Then Log(Value)

    Dim Data As Map
    Data = Value

java.lang.ClassCastException: anywheresoftware.b4a.objects.collections.Map cannot be cast to anywheresoftware.b4a.objects.collections.Map$MyMap


Any idea why the cast goes town the toilet?
 

alexb

Member
Licensed User
Longtime User
Hi Erel,

in a USER DEFINED type is it possible to combine strings with bitmaps? I have created a user defined type and last field is of type bitmap. The object is sent and received OK but on the receiving side the value for the bitmap is always null:

Example:
Type ProfileInfo (NAME As String, FIRSTNAME As String, PHOTO As Bitmap)

Obviously the Bitmap could be sent separately but with several objects being sent just one after another I am afraid the incoming streams / objects could be out of order and I have no easy way found to assign reliably the PHOTO to the rest of ProfileInfo.

Any idea?
 

ToolboxZX

Member
Licensed User
Longtime User
With regards to the example posted, is there any way to specify the directory used for the temporary files created in the procedure "astream_NewStream"?

Private Sub astream_NewStream (Dir As String, FileName As String)

I tried to alter the value of the public variable "TempFolder" in the initialization routine but that does not appear to affect where these temporary files are created.

Public Sub Initialize (TargetModule As Object, EventName As String)
target = TargetModule
event = EventName
If File.ExternalWritable Then
TempFolder = File.DirDefaultExternal & "/tmpfiles"
Log(TempFolder)
Else
TempFolder = File.DirInternalCache
End If
End Sub

They always appear in the default external folder.
 

ToolboxZX

Member
Licensed User
Longtime User
Please use [code]code here...[/code] tags when posting code.

Note that there are now better (simpler) ways to send objects with B4XSerializator.

You need to change AStream.StreamFolder.
Erel Thank you for both items. I will look into the Serializator.

Again, with regards to the example, and your answer, where specifically would you place the "AStream.StreamFolder = whatever folder" statement?

I have tried it in various places in the example code, and the only place it appears to impact the default folder is placing it in the astream_NewStream procedure (however I know this is the wrong place because the very first stream still defaults to the default directory).
 

ToolboxZX

Member
Licensed User
Longtime User
With regards to the specific example, has anyone experienced extremely slow tranfer rates or "pauses" when using Bluetooth and asyncStreams instead of a network connection?

What I did was change the example to use bluetooth instead of a network connection. The connection is made simple enough and I can transfer a very small file (say 12 bytes) no problems at all. But when I attempt to transfer a larger file, say 1.7 megabytes, it takes a very long time.

Watching the "StreamReceived" and "StreamTotal" values with a timer, I was able to observe that the file will start to transfer, then just pause for for around 8 seconds, send a chunk of data, then pause again.

Is this a result of using prefix mode wih bluetooth or is there something else that could be causing this?

I know with regards to the example that the astreamO_NewObject event is raised when the file finally "arrives" complete, but with regards to the "B4J" sending side of things, is there a way to know when all the data has actually been written out to the destination device?

Once astream0.Write() is issued, I really didn't see a way (from the sending device) to monitor the output buffer, other than to send a message back from the receiver saying something like "okay you can disconnect I have the file".
 

KitCarlson

Active Member
Licensed User
Longtime User
I think it might be limited by the baud rate of the bluetooth to serial translation. Typical baud rates are 9600, 38,400 or 115,200. If you divide by 10, then that is bytes per second. There might be additional time between characters.
 

ToolboxZX

Member
Licensed User
Longtime User
I think it might be limited by the baud rate of the bluetooth to serial translation. Typical baud rates are 9600, 38,400 or 115,200. If you divide by 10, then that is bytes per second. There might be additional time between characters.
Yes, I could see some delay with translation, but it almost seemed like on the B4J side something else was going on to cause these very long delays in just sending one small bit of data, then just sitting there at that value for 8 seconds or so before sending another. It took something like 15 minutes or so to transfer only 1.7 megabytes and both devices were close to each other :(. I have attached a screen shot of a log example indicative of the delay. You can see that initially the data starts to transfer, then gets "hung up" and then resumes with just one "chunk" of data.
 

Attachments

  • delay example.png
    delay example.png
    13.4 KB · Views: 321
Top