Android Question This error is driving me nuts!

Troberg

Well-Known Member
Licensed User
Longtime User
Something's wrong. It might be me who has messed up (and probably is), but I have a suspicion that, just this once, it just might be Erel :).

Error log:

Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:com.troberg.dash
** Activity (main) Create, isFirst = true **
Send: MA/MainMenuUpdated
java.lang.NumberFormatException: Invalid double: "null"
at java.lang.StringToReal.invalidReal(StringToReal.java:63)
at java.lang.StringToReal.parseDouble(StringToReal.java:269)
at java.lang.Double.parseDouble(Double.java:295)
at anywheresoftware.b4a.BA.ObjectToNumber(BA.java:622)
at com.troberg.dash.cmsghub._msgsend(cmsghub.java:331)
at com.troberg.dash.cmsghub._msgsend0(cmsghub.java:371)
at com.troberg.dash.cmenupresence._setbutton(cmenupresence.java:128)
at com.troberg.dash.cscrabout._setlanguage(cscrabout.java:369)
at com.troberg.dash.cscrabout._setup(cscrabout.java:404)
at com.troberg.dash.cscrabout.callSub(cscrabout.java:424)
at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:847)
at anywheresoftware.b4a.keywords.Common.CallSubNew2(Common.java:820)
at com.troberg.dash.main._addscr(main.java:452)
at com.troberg.dash.main._registerscrs(main.java:713)
at com.troberg.dash.main._activity_create(main.java:365)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at com.troberg.dash.main.afterFirstLayout(main.java:100)
at com.troberg.dash.main.access$100(main.java:17)
at com.troberg.dash.main$WaitForLayout.run(main.java:78)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)

The error occurs in this sub:

B4X:
Sub MsgSend(From As Object, Recipient As Object, Msg As String, Args As cArgPackage) AsInt
  IfSubExists(Recipient, "MsgRecieved") Then
    Dim ThisMsg As cMsg
    ThisMsg.Initialize(From, Msg, Args)
    LogMsg(Msg,False)
    ReturnCallSub2(Recipient, "MsgRecieved", ThisMsg) '<-- Error on this line
  Else
    Logs.LogError("Listener didn't answer:" & Recipient & " (" & Msg & ")")
    ListenerUnRegister(Recipient)
    Return -1
  EndIf
End Sub

Well, here's the kicker: There is not a double involved anywhere in this. All arguments are checked, and have their proper values and are properly initialized.

Now, things get really strange: If I cut it down to a minimalistic example, it works. All the code which runs is the same, I just cut out a few thousand lines that are not even involved.

It gets even better. I've encountered the exact same problem in completely different code in another program, but there, I can't replicate it on my devices. In this case, there isn't even a double variable declared anywhere in the entire project.

See the attached file for the code. There's quite a lot of code in there, and most of it is not tested yet (I don't think I've ever done so much code without a test run before...), but it runs until the error happens. Just start the app and it will error within a second or so.

Anyone who can tell me what to do to fix this will have a serious bug fixing IOU from me. I'll really dig into any problem where I might help you. This issue is really driving me nuts.
 

Attachments

  • Dash.zip
    41.3 KB · Views: 191

thedesolatesoul

Expert
Licensed User
Longtime User
B4X:
Return CallSub2(Recipient, "MsgRecieved", ThisMsg) '<-- Error on this line
The problem is that CallSub2 always returns a String. In your case it is returning null from MsgReceived sub (I dont know why).
But as the return parameter is Int, this is cast to an Int (through Double).

So I guess the issue is why MsgReceived returns "null".
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
So looking through your project, I like how you partioning your project gearing up for a pretty large project. You must be missing a view where you can see and hide all your modules in the IDE.
cMsgHub is the most interesting, its like an EventBus. Listeners get attach and can send and receive messages to class instances that are registered and alive.
The slight issue with this is the risk of having a memory leak if you do not detach the listeners.
The other issue is if the listener is inactive, like a service or activity (or any singleton inactive object), what would CallSub return?
Also I think the check for Listener doesnt exist should also check not only for subexist (which is static), but also for if the object exists or is active? Or it just fails to respond?
Anyway I am only commenting because I think this is very very cool.
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
B4X:
Return CallSub2(Recipient, "MsgRecieved", ThisMsg) '<-- Error on this line
The problem is that CallSub2 always returns a String. In your case it is returning null from MsgReceived sub (I dont know why).
But as the return parameter is Int, this is cast to an Int (through Double).

So I guess the issue is why MsgReceived returns "null".

The thing is, if I set a breakpoint in MsgRecieved, I can see that it's never called. So, the call fails, not the return.

You do have some classes that dont return anything, those are probably returning null. Add a Return 0 or something to see if it fixes the issue.

Yep, still lots of stubs, but not when this bit is concerned.
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
So looking through your project, I like how you partioning your project gearing up for a pretty large project. You must be missing a view where you can see and hide all your modules in the IDE.
cMsgHub is the most interesting, its like an EventBus. Listeners get attach and can send and receive messages to class instances that are registered and alive.
The slight issue with this is the risk of having a memory leak if you do not detach the listeners.
The other issue is if the listener is inactive, like a service or activity (or any singleton inactive object), what would CallSub return?
Also I think the check for Listener doesnt exist should also check not only for subexist (which is static), but also for if the object exists or is active? Or it just fails to respond?
Anyway I am only commenting because I think this is very very cool.

Thanks!

As you say, I'm building the foundation for a big project. I've been hinting about a community project for a while, this is the foundation for that. I'm doing a lot of work to facilitate stuff like:

* Modularization. Parts should be pretty isolated, even though they have to coexist. Code for a part should be, as far as possible, in a separate module.
* Separation of concern. Each part should handle one thing, and nothing else.
* Providing a good framwork for common functionality.

If you are curious, I've written a lot on the project here (on architecture, on project management and on ideas to include): http://troberg.synology.me/wikidash/pmwiki.php . Use any name for username, dashguest for password.

The idea is to make a complete solution for an in-car system, preferably an Android based car computer (like these: http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20150420042317&SearchText=android car computer ) or simply a tablet or phone.

I've realized a long time ago that I can't be the expert on everything, and I don't have the capacity or time to make it all by myself. However, I can create a platform, and then other people can build parts on which they are experts, and I can build parts which I'm an expert on. All in all, we would have great fun and the potential to corner a fresh market together.
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
So doesnt that mean when CallSub2 fails (maybe it cannot find Recipient instance), it will return null and that would cause a cast error?

From the docs of CallSub:
CallSub (Component AsObject, Sub AsString) AsObject
Calls the given sub. CallSub can be used to call a sub which belongs to a different module.
However the sub will only be called if the other module is not paused. In that case an empty string will be returned.

so you need to handle this case i.e.
Dim retCallSub as String = CallSub(...)
If retCallSub <> "" then Return retCallSub
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
Don't think that's the problem either. The they all run in the same activity, and should not be paused, and only a few lines before the call, I test it with SubExists(Recipient, "MsgRecieved").
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
Just to make it clear how it should work (and does work in a small example...), here's a minimalistic project where it does work.
 

Attachments

  • MsgTest.zip
    15.5 KB · Views: 174
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
The slight issue with this is the risk of having a memory leak if you do not detach the listeners.

Missed this: Not a very big risk. As soon as I try to call a listener and it doesn't answer, I drop it. Since broadcasts will be pretty frequent, that won't take long.
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
B4X:
Return CallSub2(Recipient, "MsgRecieved", ThisMsg) '<-- Error on this line
The problem is that CallSub2 always returns a String. In your case it is returning null from MsgReceived sub (I dont know why).
But as the return parameter is Int, this is cast to an Int (through Double).

So I guess the issue is why MsgReceived returns "null".

You are onto something here. When I add this line just before the call:

Log(CallSub2(Recipient, "MsgRecieved", ThisMsg))

it logs a null. The breakpoint in MsgRecieved is not reached, so it's not something inside MsgRecieved, it's something that goes wrong with CallSub. Yet, SubExists(Recipient, "MsgRecieved") returns true, so things are not all messed up, it does find the correct sub.

So, what happens to make it miss the call?
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
Added a Log(IsPaused(Recipient)) just before the call. It returns True.

So, how can the main activity be paused when called from an object that's declared in the very same activity (and, in a single activity app...)??? And, if it's paused, how do I un-pause it?
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
If you are curious, I've written a lot on the project here (on architecture, on project management and on ideas to include): http://troberg.synology.me/wikidash/pmwiki.php . Use any name for username, dashguest for password.
Wow, that is some impressive documentation. I just got lost in there for a while, it would take me ages to write that.

Added a Log(IsPaused(Recipient)) just before the call. It returns True.
So, how can the main activity be paused when called from an object that's declared in the very same activity (and, in a single activity app...)??? And, if it's paused, how do I un-pause it?
I dont think its paused. What you passed to it was the class instance 'Me', not the activity instance 'Activity'.
This requires more thinking.
 
Upvote 0

Troberg

Well-Known Member
Licensed User
Longtime User
Wow, that is some impressive documentation. I just got lost in there for a while, it would take me ages to write that.

To be quite honest, I usually don't either. However, I was away from my dev computer for a while, and wanted to get started. So, what to do besides documenting and designing?
 
Upvote 0
Top