Android Tutorial Accessing third party Jar with #Additionaljar and JavaObject - Picasso

The #AdditionalJar module attribute (introduced in B4A v3.80) allows us to reference external jars.
With the help of JavaObject it is now possible to integrate third party jars without a wrapper.

This solution is good for "simple" libraries. If the API is complicated with many interfaces then it will be easier to create a wrapper.

As an example we will use Picasso image downloader to download images: http://square.github.io/picasso/

upload_2014-5-12_13-9-8.png


The first step is to download the third party jar and put it in the additional libraries folder.
We then use #AdditionalJar to tell the compiler to add a reference to this jar:
B4X:
#AdditionalJar: picasso-2.2.0
Note that the jar extension is omitted. You can call #AdditionalJar multiple times if multiple jars are required.

The following two subs will usually be required. They allow you to get the "context" (it will be an android.app.Activity when called from an Activity module).

This code should be added to an activity or service directly.
B4X:
Sub GetContext As JavaObject
   Return GetBA.GetField("context")
End Sub

Sub GetBA As JavaObject
  Dim jo As JavaObject
  Dim cls As String = Me
  cls = cls.SubString("class ".Length)
  jo.InitializeStatic(cls)
  Return jo.GetFieldJO("processBA")
End Sub

SS-2014-05-12_13.15.19.png


As you can see in their examples we always start by calling Picasso static method 'with'. It is more clear in the JavaDocs page: http://square.github.io/picasso/javadoc/com/squareup/picasso/Picasso.html

This sub will call the static method:
B4X:
Sub GetPicasso As JavaObject
   Dim jo As JavaObject
   'com.squareup.picasso.Picasso.with(context)
   Return jo.InitializeStatic("com.squareup.picasso.Picasso").RunMethod("with", Array(GetContext))
End Sub

Now we will implement the above Java code:
B4X:
GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("into", Array(img1))

In the second example we call a more complex API:
B4X:
'second example: Picasso.with(context).load(url).resize(50, 50).centerCrop().into(ImageView)
GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("resize", Array(50, 50)) _
   .RunMethodJO("centerCrop", Null).RunMethodJO("into", Array(img2))

The third example is more interesting. We download an image with a callback event that is raised when download completes.

The first step it to create the interface. This is done with JavaObject.CreateEvent (or CreateEventFromUI).
In this case we are implementing com.squareup.picasso.Callback: http://square.github.io/picasso/javadoc/com/squareup/picasso/Callback.html
B4X:
Dim callback As Object = jo.CreateEvent("com.squareup.picasso.Callback", "Callback", Null)
The last parameter is the default return value. This value will be used if the event cannot be raised (activity is paused for example). In this case we return Null.
The event sub:
B4X:
Sub Callback_Event (MethodName As String, Args() As Object) As Object
   If MethodName = "onSuccess" Then
     ToastMessageShow("Success!!!", True)
   Else If MethodName = "onError" Then
     ToastMessageShow("Error downloading image.", True)
   End If
   Return Null
End Sub
MethodName - The interface method name (onSuccess or onError in this case).
Args - An array of parameters passed to this method. In this case there are no parameters.
All this information is from Picasso JavaDocs: http://square.github.io/picasso/javadoc/index.html?com/squareup/picasso/Callback.html

The last step is to call the method that expects the callback:
B4X:
GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("into", Array(img1, callback))

As this library requires the INTERNET permission we need to manually add it to the manifest editor:
B4X:
AddPermission(android.permission.INTERNET)

The complete code:
B4X:
#Region  Project Attributes
   #ApplicationLabel: B4A Example
   #VersionCode: 1
   #VersionName:
   'SupportedOrientations possible values: unspecified, landscape or portrait.
   #SupportedOrientations: unspecified
   #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
   #FullScreen: False
   #IncludeTitle: True
#End Region

#AdditionalJar: picasso-2.2.0

Sub Process_Globals

End Sub

Sub Globals
   Dim img1, img2 As ImageView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   img1.Initialize("")
   Activity.AddView(img1, 0, 0, 100%x, 50%y)
   img2.Initialize("")
   Activity.AddView(img2, 0, 50%y, 100%x, 50%y)
   Dim url As String = "http://i.imgur.com/DvpvklR.png"
   'first example: Picasso.with(context).load(url).into(imageView);
   GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("into", Array(img1))
  
   'second example: Picasso.with(context).load(url).resize(50, 50).centerCrop().into(ImageView)
   GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("resize", Array(50, 50)) _
     .RunMethodJO("centerCrop", Null).RunMethodJO("into", Array(img2))
  
   'third example: download image with callback
   Dim jo As JavaObject = GetPicasso
   Dim callback As Object = jo.CreateEvent("com.squareup.picasso.Callback", "Callback", Null)
   GetPicasso.RunMethodJO("load", Array(url)).RunMethodJO("into", Array(img1, callback))
End Sub

Sub Callback_Event (MethodName As String, Args() As Object) As Object
   If MethodName = "onSuccess" Then
     ToastMessageShow("Success!!!", True)
   Else If MethodName = "onError" Then
     ToastMessageShow("Error downloading image.", True)
   End If
   Return Null
End Sub

Sub GetPicasso As JavaObject
   Dim jo As JavaObject
   'com.squareup.picasso.Picasso.with(context)
   Return jo.InitializeStatic("com.squareup.picasso.Picasso").RunMethod("with", Array(GetContext))
End Sub

Sub GetContext As JavaObject
   Return GetBA.GetField("context")
End Sub

Sub GetBA As JavaObject
  Dim jo As JavaObject
  Dim cls As String = Me
  cls = cls.SubString("class ".Length)
  jo.InitializeStatic(cls)
  Return jo.GetFieldJO("processBA")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
 

aviario

Active Member
Licensed User
Hello.

We try to print in bluetooth printer using the java library of vendor.
We have the library an a sample in Java. We use #additionaljar and javaobject to develop an sample, but we have a lot of errors.
Can you help us? Here we attached then sample in Java and our sample in b4a

Thanks.
 

Attachments

  • LinePrinterSample_Java.zip
    261.9 KB · Views: 304
  • SampleB4A_1.zip
    355.5 KB · Views: 313
  • SampleB4A_2.zip
    187.1 KB · Views: 271

hzytsoft

Member
Licensed User
hi @Erel
i use a LaserApi jar
i upload this jar and mytrycodezip
can u fix a simple demo code tell us how to use it
just like open
open ();close ()

and i post this jar doc:
import com.zz.function.LaserApi.LaserManager.java



public class LaserManager {

final static String RECEIVERACTION ;


final static String RECEIVERDATA;

open ();

close ();

SoftScan();

init();

getLaserMode();

setLaserMode();

closeLaster();

SetParam(byte[] buf, int num);

GetParam(byte[] buf, int num);

RequestRevision();

enScanSound();

disScanSound();

////////////////////////
////////////use way
/////////////////////////



1.use jar need:

<uses-permission android:name="com.zz.SystemService" />

2.first

LaserManager laserManager= new LaserManager(context);

3.

IntentFilter mIntentFilter = new IntentFilter();

mIntentFilter.addAction(LaserManager.RECEIVERACTION);

String scandata= intent.getStringExtra(LaserManager.RECEIVERDATA);

tks @Erel and ba4
 

Attachments

  • mytry.zip
    7.3 KB · Views: 231
  • A1_Function_Api_v2.4.jar
    52 KB · Views: 274

EvgenyB4A

Active Member
Licensed User
Hi
I try to use the 3rd party libray from the device manufacture. This is the serial port library.
I added the attribute:

#AdditionalJar
: dwin-serialportapi-v1.1

Sub btnOpenCom_Click
Dim UART As JavaObject
Dim fd As JavaObject
Dim port As Int = 1
UART.InitializeNewInstance("com.dwin.navy.serialportapi.SerialPortOpt", Null)

End Sub

I put breakpoint on "End Sub" and after pressing OpenCom button the program doesn't stop on breakpont as if stucked.
If I press any other button I get the error:

An error occurred:


(Line: 204) End Sub
java.lang.NullPointerException

Please let me know what is wrong.
 

Attachments

  • dwin-serialportapi-v1.1.jar
    3.4 KB · Views: 246

EvgenyB4A

Active Member
Licensed User
Run it in Release mode and check the error logs.
Thank very much for fast reply. I try in Release mode. After pressing the "OpenCom button I get message box" Unfortunately My program has stopped" and errors log as follows:
** Activity (main) Create, isFirst = true **

** Activity (main) Resume **

java.lang.ExceptionInInitializerError

at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:217)
at java.lang.Class.forName(Class.java:172)
at anywheresoftware.b4j.object.JavaObject.getCorrectClassName(JavaObject.java:251)
at anywheresoftware.b4j.object.JavaObject.InitializeNewInstance(JavaObject.java:61)
at b4a.myfirstprogram.main._btnopencom_click(main.java:379)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:163)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:77)
at android.view.View.performClick(View.java:4084)
at android.view.View$PerformClick.run(View.java:16966)
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:4745)
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:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load serialport: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at com.dwin.navy.serialportapi.SerialPortJNI.<clinit>(SerialPortJNI.java:11)
... 23 more
 

EvgenyB4A

Active Member
Licensed User
Seems like your library is missing the native so file.
I have opened on my PC an APK from vendor and found this attached libserialport.so file in \libs\mips folder.
Where should I put this file?
 

Attachments

  • libserialport.zip
    4.8 KB · Views: 219

EvgenyB4A

Active Member
Licensed User
You need the arm file not mips.
The name of the folder is so important? In my mips folder the .so file is single.
By the way, the CPU of my Android device is MIPS and not ARM.
Another note- here: https://www.b4x.com/android/forum/threads/wish-compiler-support-for-so-library-files.21726/ in post #16 you noted: "The jar file should include a folder named lib. The so file should be inside this folder."
Can I ask my vendor to recompile his source so, that jar file will include a folder named lib?
Will it help?
 

EvgenyB4A

Active Member
Licensed User
In that case then you have the correct file. Which device are you using?

You can build the jar file yourself. It is a regular zip file. Use 7zip tool.

Try to change libs to lib.
How should I organize the adding of .so file?
should it look like: lib\mips\libserialport.so ?
 

shashkiranr

Active Member
Licensed User
Hi All,

I need to use Picasso to download images and just retrieve the bitmap. I dont want to put the imageview. How can this be done?

Regards,
SK
 

DonManfred

Expert
Licensed User
Only a stupid question: can I change the name of a jar library?
if you are talking about the filename of the jar. Yes, this should be possible. Changing the filename does not change the classes inside the jar.
You just need to adapt you @dependson directive (java wrapper) or #additionaljar (b4a) to include the right file
 

joilts

Member
Licensed User
Got an error message when compiling a project:

B4A version: 5.02 (1)
Parsing code. Error
Error parsing program.
Error description: Attribute not supported: additionaljar
Occurred on line: 80
#AdditionalJar: opencv

The problem is that the code is the same one that works at another project, just made a copy and paste. It is the same B4A, with same configuration paths.
The main difference (I think) is that the code that works is all in the Main, and I copied to a Activity Module at the error project. Can it be the motive?
Thanks for your time.

UPDATE: Copied the code to Main and it worked? Is it expected?
 
Top