Android Question Correct way to create a "Dim" from Java classes without parameterless constructors?

aedwall

Active Member
Licensed User
Longtime User
I have 3rd party .java files that I know work using Java on my desktop. I have managed to create a library using them and most of the functions work. But there are a couple of .java files (classes?) that require parameters sent to them. I am ignorant about Java and constructors and other "fancy" stuff.

When I use B4x Object Browser, I see this:

initTCPlanetIntern

Type
Method
Description

Syntax
initTCPlanetIntern(sw As SwissEph, planet As int, flags As int, offset As double, precalcCount As int, precalcSafetyfactor As double)

Return Value
void

I need to do whatever it takes in order to be able to call the TCPlanet class and have it execute what it does.

Doing this:

Dim tc0 As JavaObject
tc0.InitializeArray("anywheresoftware.b4a.sample1.TCPlanet", Array(swe1, 1, 128*1024, 120)) 'planet, flags, 120

brings an error:

Installing file.
PackageAdded: package:anywheresoftware.b4a.xxxxx
:null,0
java.lang.InstantiationException: java.lang.Class<anywheresoftware.b4a.sample1.TCPlanet> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at anywheresoftware.b4a.shell.Shell.createObject(Shell.java:578)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:354)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:246)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:134)
at anywheresoftware.b4a.helen.main.afterFirstLayout(main.java:95)
at anywheresoftware.b4a.helen.main.access$000(main.java:17)
at anywheresoftware.b4a.helen.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
:null,0
java.lang.RuntimeException: Unexpected command: 97
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:414)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:246)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:134)
at anywheresoftware.b4a.helen.main.afterFirstLayout(main.java:95)
at anywheresoftware.b4a.helen.main.access$000(main.java:17)
at anywheresoftware.b4a.helen.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **


Can someone tell me what to do to make this work?

The TCPlanet.java file looks like this:

package anywheresoftware.b4a.sample1;

import anywheresoftware.b4a.BA.ShortName;

@ShortName("TCPlanet")

public class TCPlanet extends TransitCalculator
{

// private void initTCPlanetIntern(SwissEph sw, int planet, int flags, double offset)
// {
// this(sw, planet, flags, offset, 200, 1.4);
// }

public TCPlanet()
{
}

//public void initTCPlanet(int planet, int flags, double offset)
//{
// initTCPlanetIntern(null, planet, flags, offset);
//}

public void initTCPlanetIntern(SwissEph sw, int planet, int flags, double offset, int precalcCount, double precalcSafetyfactor)
{
// Check parameter: //////////////////////////////////////////////////////
// List of all valid flags:
this.tflags = flags;

etc.
}

Thank you.
 

stevel05

Expert
Licensed User
Longtime User
OK, with the source from the download I've created a jar that works. It appears that the biggest problem was that android expects a two element package name, so I changed them all to com.swisseph and built it from within an Android project (I wouldn't normally do that but it sometimes gives you pointers for errors like the above), and it worked first time.

It's not wrapped so there is no xml file, but it is accessible from JavaObject.

I attach a project that recreates one of the demo files: http://www.th-mack.de/download/contrib/AriesRising.java . Hopefully the code is commented enough that you can see what's going on.

I have used a new wrapper class I am working on, but not yet released. The aim is to make the comparison with java code and code using JavaObject more similar so it's easier to port java code. Let me know how you get on with it, just ask if you need an explanation.

The project is quite busy to look at as it shows a line for line conversion from the java code to B4a and has additional comments.

The new jar is too large to upload to the forum so you can get it from my google drive here: https://drive.google.com/file/d/0B2r-tSygjxB7LUwtQUI2Wk8xZGs/view?usp=sharing copy it to your additional libs folder.

There would be a lot of extra work to do on the library to finish a proper wrapper as the source is large and a lot of classes would need more work, this may be the quickest and easiest solution.

Hope it helps.
 

Attachments

  • se.zip
    10.6 KB · Views: 238
Upvote 0

stevel05

Expert
Licensed User
Longtime User
In case you are interested, here is the B4j version (uses the same library). I find it easier to work with non Gui code in B4j.
 

Attachments

  • B4j-se.zip
    4.8 KB · Views: 244
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
Thank you for all your hard work and help. It is getting late here - I am anxious to review all you have done. Thank you again.

>> It appears that the biggest problem was that android expects a two element package name, so I changed them all to com.swisseph

So 1 or 3 is no good? Because I never had two, only 1 or 3. Seems crazy to me. But such is life.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
You are welcome, I always learn something new when doing something like this.

It's two minimum. Not sure if there is a maximum.
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
Well, all I know at this point is that it did not work using 3 ("anywheresoftware.b4a.sample1"). Maybe it was the "com." coming first. Maybe it has to start with "com.". More later.
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
With no .xml file, the swisseph2 library is not recognized in b4a. Plus, I don't know what to do to call its methods or properties. But I do have b4j, so I will open that and see what I can see. I have never used it before, so I will be guessing my way through it.
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
I got the b4j project to run with the swisseph2.jar library, even though there is no .xml file and the swisseph2 library does not show up in my list of libraries. I'm not sure why that is, but the point is that the project runs and returns a result that is accurate. Now I have to study things and see if I can bring over what I need from b4j in order to make b4a work.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
The first statement in the project
B4X:
#AdditionalJar: swisseph2
tells the project that it needs to use the jar file that is in the libraries folder even though it doesen't appear in the libraries list (as there is no xml file). Because it is not wrapped you can't directly Dim any of it's classes and they don't appear in the intellisense drop down, but you can access them via javaObject.

This is the same in the B4a and B4j projects.

It will not be recognized in your existing project, but the project in post #22 should run.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
This B4a project uses JavaObject (and not my wrapper and less comments) so you can see the difference. You may prefer it.
 

Attachments

  • seJO.zip
    7.5 KB · Views: 259
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
The TCHouses functionality works. I tried do something similar with the TCPlanet class, but I can't get the functionality to find a result - it acts like it tries to find something, but keeps going until it runs out of calendar dates, then returns an error. Obviously, it should find a "hit", then stop. But it acts like it doesn't know where to stop. So I have to chase this down. I still want to try your code with my library and see if there is any difference. I think I prefer the JavaObject methodology to the Wrapper methodology. Just seems a bit cleaner to my brain. Thanks again for all your help.

Update: the problem was I was trying to find the date when the Moon goes retrograde. But it is never retrograde and that's why I ran out of "calendar". So it was my mistake - a stupid error on my part.
 
Last edited:
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
Steve,

Currently my project uses my SE_v201 library to do the non-TCxxx calculations and it uses your swisseph2 library for all the TCxxx calculations. Can you send me the source files you used in making swisseph2? I'd like to get to the point where I only use one library and also be able to update that library in the future if changes come along. I have all TCxxx functionality working now. Thank you for all your help.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
I've zipped and attached the source files, still in the src folder.

Hope it helps.
 

Attachments

  • src.zip
    495.8 KB · Views: 250
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
Steve, Apparently your swisseph2 library uses StringBuffer in swe_calc_ut and b4a does not like StringBuffer. In my source code I had to replace all instances of StringBuffer with StringBuilder. So apparently when I call swe_calc_ut with serr as StringBuilder I get the error message "java.lang.RuntimeException: Method: swe_calc_ut not matched." - because passing a StringBuilder is not the same as passing a StringBuffer. And b4a does not accept StringBuffer.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
You can create a StringBuffer object from a string using JavaObject. The documentation is here: http://developer.android.com/reference/java/lang/StringBuffer.html

B4X:
Dim TestStr As String = "Test"
Dim StringBuff As JavaObject
StringBuff.InitializeNewInstance("java.lang.StringBuffer",Array(TestStr))

Then pass StringBuff to swe_calc_ut

Then you won't have to rewrite all the classes that use it.
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
If there are a lot of them, you could use a sub like this:

B4X:
Sub AsStringBuffer(Str As String) As JavaObject
    Dim StringBuff As JavaObject
    StringBuff.InitializeNewInstance("java.lang.StringBuffer",Array(Str))
    Return StringBuff
End Sub

And Pass AsStringBuffer("Test")
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
I've zipped and attached the source files, still in the src folder.

Hope it helps.

When I make a .jar file in Eclipse the resulting library does not work. Very strange. So I will use 2 libraries, yours for TCxxx calculations and my SE_v201 for the the other calculations.

BTW, I sent you a donation as thanks for all your help. I trust you received it.
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
How much code is involved in the other calculations, it may be worth reworking them so you can use a single library. The resulting size of the APK will be larger with two libraries.

When I make a .jar file in Eclipse
Yes I had that problem initially, and thought it was just the package name. Perhaps creating an Android Project within eclipse cured more than just that.

I've been out this evening, but just checked and yes, I did receive your donation, Thanks very much.
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
You can create a StringBuffer object from a string using JavaObject. The documentation is here: http://developer.android.com/reference/java/lang/StringBuffer.html

B4X:
Dim TestStr As String = "Test"
Dim StringBuff As JavaObject
StringBuff.InitializeNewInstance("java.lang.StringBuffer",Array(TestStr))

Then pass StringBuff to swe_calc_ut

Then you won't have to rewrite all the classes that use it.

Hey, that worked - I was surprised. Thanks again.

But now that I check it more closely, I'm always getting Moshier calculations and not Swiss ephemeris calculations. So I think I will stick with 2 separate libraries.

How much code is involved in the other calculations, it may be worth reworking them so you can use a single library. The resulting size of the APK will be larger with two libraries.

Yes I had that problem initially, and thought it was just the package name. Perhaps creating an Android Project within eclipse cured more than just that.

Another 750 KB in an .apk file is nothing, IMHO. I'm not sure if my next project will even need the TCPxxx calculations, but in case I need them down the road I wanted to see if I could make them work now, before the project gets too intense. Like you, I'm learning with everything I try. I think 750 KB is a small price to pay if very exact calculations are necessary. The Moshier calculations are very close to the Swiss ephemeris calculations, so it might be a toss up. But it's good to know your options and what does what.

Yes, your .jar file was 742 KB and mine was 526 KB, so something is different. So even with the same source code, Eclipse handles things differently than Android. But after 5 long days of all this, I'm not sure I care enough to continue to battle it. I think my next step is go through my code and tweak it from all the mess it is now with all the commented out code, etc. Maybe then I will have a clearer head.
 
Upvote 0

aedwall

Active Member
Licensed User
Longtime User
Steve - your swisseph2 .jar file shows .class files and my Eclipse swisseph2 .jar file shows .java files. So apparently yours are compiled and mine are just source code. Perhaps that explains things - and why my .jar file doesn't find the classes like it is supposed to.
 
Upvote 0
Top