Android Question AsyncStream passes a null object to the _error sub

sorex

Expert
Licensed User
Longtime User
Hello,

I'm updating an old app hopefully to stabalize it a bit (seems to go in endless loop sometimes on newer phones).

It's build on async streams and while I used a several try/catch blocks to intercept errors I'm trying to do it in a more clean way.

Now I noticed that the async stream _error function sometimes recieves a null object which makes my connection closing routine freak out on the .isInitilized check.

error:
05/03/2024 11:18:46 : 192.168.11.5 java.lang.NullPointerException: Attempt to invoke virtual method 'boolean anywheresoftware.b4a.randomaccessfile.AsyncStreams.IsInitialized()' on a null object reference ( java.lang.NullPointerException: Attempt to invoke virtual method 'boolean anywheresoftware.b4a.randomaccessfile.AsyncStreams.IsInitialized()' on a null object reference

What's the right way to detect this null object so that I can skip the closing sub?
And why does it pass this null object and not the actual streaming one?
 

emexes

Expert
Licensed User
What's the right way to detect this null object so that I can skip the closing sub?

I take it that If PotentiallyNullObject = Null Then doesn't work?

(or maybe If PotentiallyNullObject Is Null Then)

(or wrap the .IsInitialized test inside a Try...Catch but it sounds like you're up to your neck in those already šŸ¤£)

And why does it pass this null object and not the actual streaming one?

I am just guessing here, but perhaps AsynchStreams crashed out but didn't successfully close the feeder stream, and that feeder stream still (somehow) knew the name of the error event to call. šŸ¤”
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
I take it that If PotentiallyNullObject = Null Then doesn't work?

I don't know that's why I'm asking ;)

the problem is that I didn't get this error om my test phones yet or I don't know when this happend or how I can force that situation/error.

I tried manual disconnects, disabling wifi etc but in my case the stream just reconnects without problems.

The problem is that when I apply the change my colleague needs to manually update the app on a dozen phones so I prefer waiting for the right way than just guessing.
 
Upvote 0

emexes

Expert
Licensed User
the problem is that I didn't get this error om my test phones yet or I don't know when this happend or how I can force that situation/error.

I feel your pain šŸ» non-reproducible errors suck.

I am pretty sure that, if no better solution arises, then an If PotentiallyNullObject = Null test before the PotentiallyNullObject.IsInitialized would work as a last resort safety net to catch app before it goes down in flames. :oops:
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
It's build on async streams and while I used a several try/catch blocks to intercept errors I'm trying to do it in a more clean way.

Now I noticed that the async stream _error function sometimes recieves a null object
I wonder if it is related to this?
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
@emexes : thanks for the hint. this seems to compile fine and hopefully bypasses the problem

B4X:
If senderAsyncStream=Null Or senderAsyncStream.IsInitialized=False Then Return

@OliverA : I doubt it is related to the problem above as I'm still on version 11.50 on this machine.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
I have a gut feeling it could still crash as you cannot test isInitialized on a null object.
test for null first then test for isInitiailized
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I have a gut feeling it could still crash as you cannot test isInitialized on a null object.
test for null first then test for isInitiailized
If the first condition is true (in this case senderAsyncStream is Null), then it will short circuit and will not test the 2nd condition. The only time the 2nd condition will be tested if the first condition fails, meaning that senderAsyncStream is NOT null and therefore one can safely use the Object's methods.
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
hmm, that solved the crash but now I see my log window being flooded with the log line that is in the _error sub.

for some reason when I disconnect the stream on the listener side I now get endless _error calls.

it didn't do that earlier when I was testing this.

the order I use to disconnect is stop playing sound stream, close async stream, close socket.
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
even more bizar... when I close the listener app the flooding keeps going :)

even when disabling my closing routine it keeps flooding the log window.

B4X:
Sub Astream_Error
    Log("error sender:" & Sender)
    'CallSub2(Main,"writeLog","BROA> Stream error")
    'closeConnection(Sender)
End Sub

when I connect again on the listener side it start playing audio again but the flooding of the error won't stop.
 
Last edited:
Upvote 0

sorex

Expert
Licensed User
Longtime User
it gives a broken pipe error but as the sender of the error is a null object I can't find in my connections list which socket I need to close.
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
ok, I seem to have a workaround.

the null or initialized check to exit the sub it not needed as it keeps the error loop alive.

my close connection has 2 main loops.

first it scans the connection list to figure out what ip the request is coming from.

in the second loop it checks all connections and closes all those from the found IP just in case there are multiple.

in the second loop I just change the check for the found ip to (found ip or "") the ip value is "" when no ip was found in the first loop (in case of null object)

so it either closes the given IP connections or all connections when a null object passes.

not clean but not a real issue either as the listeners will reconnect after max 15 seconds.

why the _error keeps getting called when the socket is not closed I don't know.
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I'm looking at the source here: https://github.com/AnywhereSoftware...AShared/src/anywheresoftware/b4a/BA.java#L366

From what I can tell, if the event is queued via the line
B4X:
addMessageToPausedMessageQueue(event, this);
then the sender information is lost. If that is true, it may be that you have to encapsulate each AsyncStream object within another Class module that tracks that AsyncStream's objects error events and then closes the AsyncStream object associated with the class, instead of relying on the Sender object of the event. I hope this logic makes sense...
 
Upvote 0
Top