Android Question [RESOLVED]Raised Exception in Inline Java Code in Class with Multiple Initializors

cimperia

Active Member
Licensed User
Longtime User
As I was playing with the code posted by Erel in this tutorial: Inline Java Code I added a second Initialize method Initialize2.
B4X:
'Class module Class1
Sub Class_Globals
   Private nativeMe As JavaObject
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
   nativeMe = Me
   Log(nativeMe.RunMethod("Multiply", Array (10)))
End Sub

Public Sub Initialize2
   nativeMe = Me
   Log(nativeMe.RunMethod("Multiply", Array (10)))
End Sub

#If JAVA
private int mm = 100;
public int Multiply(int i) {
   return i * 2 + mm;
}
#End If

If you call Initialize2, without first calling Initialize, the Me object is NULL and therefore the assignment nativeMe = Me will raise an exception:

B4X:
Error occurred on line: 18 (Class1)
java.lang.NullPointerException: null receiver
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:712)
   at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:340)
   at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:244)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:132)
   at b4a.example.main.afterFirstLayout(main.java:103)
   at b4a.example.main.access$000(main.java:18)
   at b4a.example.main$WaitForLayout.run(main.java:81)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5257)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

How can I retrieve the context from Initialize2?
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
I think you could add a Map (or List) as "param array" to the Inizitialize routine, then you can choose between different initializations of your class.

' Here a description for each type of initialization:
' Pass... to...
' Pass... to...
Initialize(mapParams As Map)

Also, first element of the Map could be:
mapParams.Put("InitType", INIT_DEFAULT)
where INIT_DEFAULT is a public constant
INIT_XXX
...

("InitType" or "InitVersion"? Mah :D)


[EDIT: the default initialization should be a Null map, more simply, but I know you understood what I meant]
 
Last edited:
Upvote 0

cimperia

Active Member
Licensed User
Longtime User
There is only one initialize method for classes and it is the Initialize sub.

OK. But, is there a way from another method to initialize the class? I should be able to get hold of the processBA somehow.

I have been trying to convert a wrapper library that I wrote in Java, which offers multiple Initialize methods. I want to convert it to BA4 and offer the code to the community, but this seems to be a show stopper.

B4X:
//@DependsOn(values = { "rangeseekbar" })
@Version(1.00f)
@ShortName("RangeSeekBar")
@BA.Events(values={"Change"})
public class RangeSeekBarWrapper<T extends Number> extends ViewWrapper<RangeSeekBar<T>> implements DesignerCustomView
{
  // Throw away variable to communicate between Initialize2() and _initialize()
  boolean singleThumb = false;

  /**
  * Initialize the RangeSeekBar widget with AbsoluteMinValue = 0 and AbsoluteMaxValue = 100.
  * @param EventName set to a non-null string to enable Change event.
  */
  public void Initialize(final BA ba, String EventName) {
  _initialize(ba, null, EventName);
  }

  /**
  * Initialize the widget as a SeekBar - i.e. with one thumb only.
  * Defaults: AbsoluteMinValue = 0 and AbsoluteMaxValue = 100.
  * @param eventName set to a non-null string to enable Change event.
  */
  public void InitializeAsSingleThumb(final BA ba, String eventName) {
  this.singleThumb = true;
  _initialize(ba, null, eventName);
  }

  /**
  * Initialize the RangeSeekBar widget with AbsoluteMinValue = min and AbsoluteMaxValue = max.
  *If singleThumb is set to true, then a simple SeekBar is initialized.
  *
  * @param min Absolute minimnum value
  * @param max Absolute maximum value
  * @param singleThumb set to true, a SeekBar is initialized, instead of a RangeSeekBar
  * @param eventName set to a non-null string to enable Change event.
  */
  public void Initialize2(final BA ba, T min, T max, boolean singleThumb, String eventName) {
  this.singleThumb = singleThumb;
  _initialize(ba, null, eventName);
  getObject().setRangeValues(min, max);
  }
 
Last edited:
Upvote 0

cimperia

Active Member
Licensed User
Longtime User
I have found a possible solution to this. I have tested it and it works well, though I don't know whether it's the "proper" way to go about it.
Basically any method can be an initializer. You have to make sure to call the Class_Globals proc. and then to instantiate the class object with default constructor. (After reading Luca's comment, I've realized this 2nd instruction was not necessary).

I have done just that in Initialize2 and it works as expected.

B4X:
'Class module
Sub Class_Globals
   Private nativeMe As JavaObject
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
   nativeMe = Me
   Log(nativeMe.RunMethod("Multiply", Array (10)))
End Sub

Public Sub Initialize2
  'Call Class_Globals to ensure that variables are declared etc...
  Class_Globals

  'It turns out the following instruction is unnecessary.
  'Instantiate Class object with default constructor
  'nativeMe.InitializeStatic(Application.PackageName & ".class1")

  'Assign the class object to nativeMe in the expected format
  nativeMe = Me

  Log(nativeMe.RunMethod("Multiply", Array (10)))
End Sub

#If JAVA
private int mm = 100;
public int Multiply(int i) {
   return i * 2 + mm;
}
#End If
Edit: 4/12/2015
This solution is not quite correct. For a better and safer way to do this have a look at this post.
 
Last edited:
Upvote 0

cimperia

Active Member
Licensed User
Longtime User
Wow... then it should work regardless of Inline Java or I'm wrong?
You are right. I have been able to duplicate my multiple Initialize subs without any need of Inline Java.
 
Upvote 0

cimperia

Active Member
Licensed User
Longtime User
Let us know whether it works for you too ;)
 
Upvote 0

cimperia

Active Member
Licensed User
Longtime User
This your "discovery" should be published in a more suitable place, @cimperia

[I don't know where :(... Code snippets?]

Good idea, I'll do just that ... later on.
 
Upvote 0
Top