Android Tutorial Inline Java Code

The next versions of B4A (4.30) and B4J (2.80) will allow you to embed Java code inside your B4X code. B4i supports similar feature with Objective C.

The purpose of this feature is to make it easier to access third party SDKs and also to allow developers to add existing Java code snippets to their projects.

Adding Java code is done with an #If Java block:
B4X:
#If JAVA
public String FirstMethod() {
   return "Hello World!";
}
#End If

You need an instance of JavaObject to access the Java methods:
B4X:
Sub Process_Globals
   Private NativeMe As JavaObject
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     NativeMe.InitializeContext
   End If
   Dim s As String = NativeMe.RunMethod("FirstMethod", Null)
   Log(s) 'will print Hello World!
End Sub
The Java code can also include imports. The compiler will find these imports and add them at the top of the class.

The Java code will be added at the end of the class. Right before the closing bracket.

Methods added to Activity or Service modules will be executed with the component context ('this' will be the activity or service instance).

Hooks

Hooks are similar to the standard events but they run Java methods. Hooks are mainly used by SDKs that require you to add code in the various Activity events.
Note that there are no hooks in B4J implementation.

For example the following code will run in the standard Activity onCreate method (before the call to setContentView):
B4X:
#If JAVA
public void _onCreate() {
   requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
}
#End If

Activity hooks:
_onCreate()
_onResume()
_onPause()
_onDestroy()
_onStop()
_onStart()
_onPrepareOptionsMenu (android.view.Menu menu)
_onnewintent (android.content.Intent intent)
boolean _onCreateOptionsMenu (android.view.Menu menu) <--- If you return true from this method then the standard B4A code in onCreateOptionsMenu will not run.
boolean _onkeydown (int keyCode, android.view.KeyEvent event) <-- Return true from this method to return true from the native onKeyDown (and skip Activity_KeyPress event).
boolean _onkeyup (int keyCode, android.view.KeyEvent event) <-- same comment as above

Service hooks:
_onCreate()
_onStartCommand(Intent intent, int flags, int startId)
_onDestroy()

Tips

- The methods you add should be public methods.
- Methods in static code modules should be public static.
- See the attached project. It shows how to call Java methods in all types of modules.

Don't misuse this feature. There are no performance advantages for using it and it can make your project more difficult to debug and maintain.
 

Attachments

  • InlineJava.zip
    12.7 KB · Views: 4,047
  • B4J-InlineJava.zip
    1.2 KB · Views: 2,424
Last edited:

stevel05

Expert
Licensed User
Longtime User
It should work, try this:

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim NativeMe As JavaObject
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    NativeMe.InitializeContext  
    NativeMe.Runmethod("methodName",Array("String1","String2"))
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

#If java

public void methodName(String s1,String s2){
    BA.Log(s1 + " " + s2);
}
#End If
 

Johan Schoeman

Expert
Licensed User
Longtime User
This added functionality is better than cheese! Great, great, great addition Erel!
Have posted two simple examples here and here making use of the new feature
 
Last edited:

giacomo-italy

Member
Licensed User
Longtime User
It depends on the complexity of the wrapped library. However you can add a reference to the library with #AdditionalJar attribute and then use inline Java code or JavaObject to access its API.

See this tutorial: Accesing third party Jar with #Additionaljar and JavaObject

Hello Erel,
I am one of many who would like to use opencv in B4A.
Do you think can I use the library opencv-2410.jar (file in opencv/build/java/... ) with #AdditionalJar,
and use inline Java code to access it?
For example embed Java code like the code shown below.
It is a java example (face detector) using methods of java opencv.

Is this correct?
Or am I astray?
Thanks a lot.

code:
------------------------------------------------------------------------------------------------------
package com.shekhar.facedetection;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.objdetect.CascadeClassifier;

public class FaceDetector {

public static void main(String[] args) {

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.out.println("\nRunning FaceDetector");

CascadeClassifier faceDetector = new CascadeClassifier(FaceDetector.class.getResource("haarcascade_frontalface_alt.xml").getPath());
Mat image = Highgui
.imread(FaceDetector.class.getResource("shekhar.JPG").getPath());

MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);

System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));

for (Rect rect : faceDetections.toArray()) {
Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}

String filename = "ouput.png";
System.out.println(String.format("Writing %s", filename));
Highgui.imwrite(filename, image);
}
}
-------------------------------------------------------------------------------------------
 

stu14t

Active Member
Licensed User
Longtime User
This seems an ideal solution for the Parse sdk, which has only been partially wrapped leaving some of the methods / objects not accessible (using the wrapper).

Is it OK to use the wrapper and inline java code to access the sdk together, I mean, they won't upset each other?
 

stu14t

Active Member
Licensed User
Longtime User
Parse provides a lot of example java code, how could this be used?

I would really like to see tutorials on In-line coding
 
Last edited:

giacomo-italy

Member
Licensed User
Longtime User
You can add any Java you like. However if you are not familiar with Java then it will be difficult to use this feature with non-simple code.

I'll start experimenting with OpenCV following this road.
Obviously I will start with the simplest things, of course also studying java.
I only ask for confirmation:
i have installed opencv 2.4.10 on Windows PC on which I use B4A,
then in the installation folder of opencv i reach the folder opencv/build/java/...,
and i find the file opencv-2410.jar,
this jar file that i incorporate with #AdditionalJar is the right file for working in opencv with java code ?
Thanks again.
 

giacomo-italy

Member
Licensed User
Longtime User
You need to check their documentation. Is this the jar you need to add to your Android project?

To be or not to be (..the right file..) that is the question!
It is possible that it is not, because is the file to build with Java in Windows.
Instead need I to find the jar file in the build of java in Android...?
I tried. But in the installation of opencv under Android, there is not a .jar file in the build folder.
Should be compiled opencv by the C++ with the Android SDK+NDK?
(The thing is complicated, and a little out of my league...)
What do you think about this?
Thanks
 

giacomo-italy

Member
Licensed User
Longtime User
Someone of goodwill, with more knowledge than me,
can think and give a tip on how to use OpenCV, maybe is best JavaCV (https://github.com/bytedeco/javacv),
with this new features of b4a (#Additionaljar and java code)?
Thanks

P.S.:
In https://github.com/bytedeco/javacv we can obtain JavaCV 0.10 binary archive:
  • javacv-0.10-bin.zip
The binary archive contains builds for Linux, Mac OS X, Windows, and Android
(it contain the files: javacv-android-x86.jar, opencv-android-x86.jar, ffmpeg-android-x86.jar etc..
as well as javacv-android-arm.jar, opencv-android-arm.jar, ffmpeg-android-arm.jar etc..).
The hamletic doubt about desired JAR files to use is dissolved? We can use these jar files?
The *-android-arm.jar or *-android-x86.jar files?
 

giacomo-italy

Member
Licensed User
Longtime User
I check the documentation about OpenCV for Android.
OpenCV for Android is designed as a standalone library APK.
(We can download OpenCV for Android from http://opencv.org/downloads.html and cliking on 'OpenCV for Android',
and downloading 'opencv-android-sdk' zip file).
We also can install the OpenCV Manager directly from Google Play store.
OpenCV Manager is an Android service targeted to manage OpenCV library binaries on end users devices.
It allows sharing the OpenCV dynamic libraries between applications on the same device.

But we need to include the OpenCV SDK as an Android library into our own Android project.
Then we can directly write the Java code and use opencv in our app.
(see the example 'How to acquire camera images using OpenCV' here:
http://developer.sonymobile.com/kno..._tutorial/get-started-with-opencv-on-android/ )

So after reading continuously a huge amount of information on the web,
my conclusion is that if there is a way to include the OpenCV SDK (designed as a standalone library APK: OpenCV_binary_pack_armv7a.apk, OpenCV_Manager_2.19_armv7a-neon-android8.apk ) as an b4a library into our own b4a project,
we will be able to use opencv, using java code that refers directly to the library, inside our b4a app.

Erel, then I ask you (as a last question on the subject, I promise) if we can
include the opencv sdk as the standalone library APK in B4A (and eventually how to include it)
and so we can write java code that refers directly to the library.

Thanks for your great patience in listening to us.
 

Siam

Active Member
Licensed User
Longtime User
hello,

how can i call a java class? like this:

B4X:
#If JAVA
import java.lang.Math;
import java.lang.Float;
public class AquaLib {
    public Float one(Float kh,Float co) {
    float x = (float) Math.round((7.90+Math.log(kh/(2.8*co))/Math.log(10))*100)/100;
    return x;
    }
    public Float two(Float kh,Float co) {
    float x = (float) Math.round((7.90+Math.log(kh/(2.8*co))/Math.log(10))*100)/100;
    return x;
    }   
    public Float tree(Float kh,Float co) {
    float x = (float) Math.round((7.90+Math.log(kh/(2.8*co))/Math.log(10))*100)/100;
    return x;
    }   
    public Float four(Float kh,Float co) {
    float x = (float) Math.round((7.90+Math.log(kh/(2.8*co))/Math.log(10))*100)/100;
    return x;
    }   
}
#end if

with :

B4X:
NativeMe.InitializeStatic("AquaLib")
Dim s As Float =  NativeMe.RunMethod("one",Array As Object(kh,co))

i get :

java.lang.ClassNotFoundException: java$lang$AquaLib

what is my error ?

lg

andy
 

mlc

Active Member
Licensed User
Longtime User
Hello,

If I test this code, the result is correct.

B4X:
Sub Process_Globals
    Private nativeMe As JavaObject
End Sub
Sub Service_Create
    nativeMe.InitializeContext
End Sub

Sub Service_Start (StartingIntent As Intent)
    Dim l As Long
    l = nativeMe.RunMethod("FreeSpace", Array(File.DirRootExternal))
    Log("l = " & l)

End Sub

#If JAVA
import java.io.File;
import android.content.Context;

public long FreeSpace(String Pathf) {
      File f = null;
      long v;
      boolean bool = false;
     
      try{
         // create new file
         f = new File(Pathf);
        
         // get number of unallocated bytes
         v = f.getFreeSpace();
        
         // true if the file path exists
         bool = f.exists();
        
         // if file exists
         if(bool)
         {
            // prints
            return v;
         }
         else
        {
         return 0;
         }
      }catch(Exception e){
         // if any error occurs       
       return 0;
     
      }
}

#End If

But if I copy exactly this code to my project (it is also a service), get this error:

line 40 = nativeMe.InitializeContext

B4X:
** Service (serverservice) Create **


Error occurred on line: 40 (serverservice)
java.lang.NoSuchFieldException: context


    at java.lang.ClassCache.findFieldByName(ClassCache.java:446)
    at java.lang.Class.getDeclaredField(Class.java:666)
    at anywheresoftware.b4j.object.JavaObject.InitializeContext(JavaObject.java:64)
    at mlc.wifitransfer.serverservice._service_create(serverservice.java:6308)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:302)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
    at mlc.wifitransfer.serverservice.onCreate(serverservice.java:48)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:1949)
    at android.app.ActivityThread.access$2500(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:989)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3691)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
    at dalvik.system.NativeStart.main(Native Method)
** Service (serverservice) Start **

Which could be the problem?

Thanks
 
Top