I think I got it.
Erel suggested that I check if I had the AStream_Terminated() event.
I did but the app still crashed.
It turns out that after I added Try/Catch brackets around the AStream.Initialize statement in the ConnectedToServer function (after the socket is seemingly opened), the Terminate event was then called when the socket closed.
So AStream_Initialize does not fail, but the connection terminates some time later.
Then there was a secondary issue:
I had this in the AStream_Terminated event:
Log( "AStream_Terminated: " & LastException.Message )
The problem was that the "LastException" message was causing a crash too.
I replaced that line with:
Log( "AStream_Terminated" )
and now the event is properly handled.
Interestingly, the socket is still being opened, the Terminated event occurs a bit after trying to open AStream, and sometimes that occurs a second or two (!) after the socket is opened (note that this is early Sunday morning, the machine and the network are lightly loaded). I have no idea why the long delay but it no longer crashes the app and it properly reports the socket as closed, so I am happy.
Finally, I unplugged the server while being connected to see what happened.
After a minute or so, I got the AStream_Error event:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at anywheresoftware.b4a.randomaccessfile.AsyncStreams$AIN.run(AsyncStreams.java:216)
at java.lang.Thread.run(Thread.java:748)