About the author
In XE5, Embarcadero introduced a new object oriented way of calling into any Android API. Before looking at it, let's look at the old way of doing it.
var Cls: JClass; Mid: JMethodID; ... Cls := JNIEnv.FindClass('TestClass'); if Cls = nil then begin WriteLn('Can''t find class: TestClass'); Exit; end; Mid := JNIEnv.GetStaticMethodID(Cls, 'printHello', '()V'); if Mid = nil then begin WriteLn('Can''t find method: printHello'); Exit; end; JNIEnv.CallStaticVoidMethod(Cls, Mid, []); // [] - no parameters
Imagine the tedium involved when there's plenty of methods to be called. In XE5, a class known as TJavaGenericImport takes two interfaces, one declaring all the Java methods for a class, and one declaring all the class methods, and allow them to be called directly. See my previous posting for further details.
So, if in Java, you have an instance of TestClass in tc, and you call it like this:
tc.printHello();
in Delphi, you can do the same thing as well!
All you have to do is write two interfaces, one describing the class methods, and one describing the instance methods and then create a new class that inherits from TJavaGenericImport and specify the two interfaces as generic parameters. So, given the following Java class that was seen earlier:
public class TestClass { public TestClass() { } public TestClass(String msg) { } public void printHello() { } public static float[] getTestFloat() { } public static long[] getTestLong() { }
the following would be what you would need to write:
JTestClassClass = interface(JObjectClass) ['{6E1DA723-41BE-4E0A-8103-B2FDED2E9307}'] { Constructors } function init: JTestClass; cdecl; overload; function init(msg: JString): JTestClass; cdecl; overload; { Class Methods } function getTestFloat: TJavaArray<Single>; cdecl; function getTestLong: TJavaArray<Int64>; cdecl; end; [JavaSignature('cx/ath/journeyman/TestClass')] JTestClass = interface(JObject) ['{6D521D7D-863C-43E7-A7CF-EB57A7D3378F}'] { Instance Methods } procedure printHello; cdecl; end; TJTestClass = class(TJavaGenericImport<JTestClassClass, JTestClass>) end;
The Java way:
TestClass tc = new TestClass(); // or new TestClass("Hello"); tc.getMinLong();
To construct an instance of TestClass, call TJTestClass.Create, or TJTestClass.JavaClass.init. Here's the Delphi way,
var LTestClass: JTestClass; ... LTestClass := TJTestClass.Create; // or LTestClass := TJTestClass.JavaClass.init(StringToJString('Hello')); LTestClass.getMinLong;
The call StringToJString transforms the given Delphi string to its Java equivalent. Since XE5 came out, I've been working on writing an application that can convert any Java class to its equivalent Delphi/Android interface as there are some Android classes that were not declared, and I'm pleased to announce that the effort is now completed. To purchase the tool, visit the Android2DelphiImport tool site. To load an external JAR, see my other post.
Generating the import unit for Google Cloud Messaging for Delphi.
I've tested this out for importing Android APIs and it works fabulously! What a great resource!
A method pointer is now the same as a global procedure, ie, procedure of object = procedure.