Java Question Call a B4A Sub from Java in a synchronized way

JordiCP

Expert
Licensed User
Longtime User
Perhaps it is very obvious, but I am a bit stuck thinking about this and any help will be welcome...

I am developing a library with several classes. One of these classes executes some tasks in a different thread.

This thread must call a Sub in B4A, that will do some custom work. This B4A Sub has to be called synchronously (so will be executed in that thread) : it will modify some data and the thread will continue working with it.

Here is my doubt (and perhaps where I am wrong):
  • I think I can't use "raiseEvent","raiseEventFromDifferentThread",.... since they will be executed asynchronously. Is it right?
  • If so, how can I directly call a BA Sub from Java?

Thanks in advance:)
 

Roycefer

Well-Known Member
Licensed User
Longtime User
Does your Java code have compile-time access to the object that "owns" the Sub (Activity, Service or instance of a Class)? If so, just call it as you would any Java function. B4A Subs will be lower-cased and an underscore "_" will be prepended to the Sub name.

If not, you can use anywheresoftware.b4a.keywords.Common.CallSubNew.

Alternatively, you can do the following (this is Java reflection):
B4X:
Class[] parameterTypes = {};   //This will be an array indicating the types of the arguments to be passed to your Sub
Object o = c.getDeclaredMethod("_" + SubName.toLowerCase(), parameterTypes).invoke(OwningObject, new Object[]{}); 
//That new Object Array will be the arguments passed to OwningObject.SubName. The Object o is the return value of OwningObject.SubName
 

JordiCP

Expert
Licensed User
Longtime User
Thanks a lot Roycefer, will try it!

The Sub will be in main activity but its name will be passed to the class on initialization

So, if I understood correctly, let's suppose my Sub name is named "processor" and argument to be passed is myArg. Would be something like this?
B4X:
Object result = anywheresoftware.b4a.keywords.Common.CallSubNew2(ba,this,"_processor",myArg);
 

JordiCP

Expert
Licensed User
Longtime User
I must be doing something wrong, I know, but don't know what. My best approach is that it didn't throw error, but the Sub was not being called...:(

Tried to simplify the Sub with no parameters, and also to tried to make the call from outside the thread (just in case) with same results.

Java code
B4X:
anywheresoftware.b4a.keywords.Common.CallSubNew(ba,"main","_processor");  // also tried with "processor"

BA Sub
B4X:
Sub processor
  Log("Hello!!")
End Sub

Waiting for the light :confused:
 

Roycefer

Well-Known Member
Licensed User
Longtime User
In your most recent post, you're using "main" as the second argument to CallSubNew. That's a String. It should be the object itself, main. Also, are you sure you're using the correct ba? If you're calling this Java code from within the Main Activity, you'll probably want to use the activityBA. It is for this reason that I prefer my last option (using Java reflection). No messing about with BAs....
 

JordiCP

Expert
Licensed User
Longtime User
ba.raiseEvent is synchronously (you can see that it returns a value).
Oops, my fault. I should have checked it :(

Now it is solved! --> The reason it didn't work was that during my tests I was invoquing everything (initializing my class and make the call) in Activity_Create, and this call did not take effect (but didn't throw any error)

Both options work
B4X:
   anywheresoftware.b4a.keywords.Common.CallSubNew2(ba,"main","myframeprocessor",mFrameChain[1 - mChainIdx]);
B4X:
   ba.raiseEvent(ba,"myframeprocessor",mFrameChain[1 - mChainIdx]);

Is there any advantage (in terms of efficiency, or other factors I should care about) on using one over the other? This will be called on each frame delivered by the camera and the processed results will be drawn on a surfaceView.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You should use ba.raiseEvent. CallSubNew2 eventually calls it as well.
in Activity_Create, and this call did not take effect (but didn't throw any error)
1. This means that your code is raising synchronous events. Make sure to mark the relevant method with @RaisesSynchronousEvents.
2. Use ba.raiseEvent2 and set the allowDuringPause parameter to pause.
 
Top