Android Guidelines for Using Native Function APIs in Quantum Visualizer Classic

To use the Native Function APIs in Visualizer Classic, follow these guidelines:

Category Description
Accessing classes

To access a class, use the following API:

java.import

This API helps you import any Android native class into JavaScript. You must use the keyword "new" to instantiate (create an object) an instance of a JavaScript class. All the APIs, methods, constants, and all members of the native class are directly accessible with the instantiated object.

Signature

JavaScript: java.import (native_class_name)

Input Parameters

native_class_name [String] - Mandatory

Specifies the native class name including the package name that you want to use in JavaScript.

Return Values

Returns a JavaScript constructor function that can be used to instantiate the class. The constructor function also has properties that map to the following:

  1. Static fields: Any static fields that the Java class exposes.
  2. Static methods: Any static methods that the Java class exposes.
  3. Inner classes: Any inner classes that the Java class defines.

Platform Availability

Available on Android platform.

JavaScript Example

//Sample code
var Thread = java.import('java.lang.Thread');
Instantiating Java classes

The instances of a Java class can be created with the keyword "new" on the constructor function returned by the API java.import. For example,

Example 1

var ArrayList = java.import('java.util.ArrayList');
var alist = new ArrayList();

Example 2

var ArrayList = java.import('java.util.ArrayList');
var a = new ArrayList();
a.add(1);
a.add(2);
var alist = java.newInstance('java.util.ArrayList', a);
alert(alist.size());

If the class has overloaded constructor methods, each of them can be called with the keyword "new" by passing the correct parameter types.

Defining a new method or a new class (which contains new methods) that is not in native, is not supported.

Alternatively, the API java.newInstance can be used to instantiate a Java class by passing the instance name as its first argument and the arguments to the constructor method enclosed in a JavaScript array as the second argument.

java.newInstance('class_name', [arg1, arg2, ...]);
Invoking static methods

Static methods can be accessed as properties of the constructor function returned by the API java.import. Static methods can be invoked using the following syntax:

var c = java.import('...');
c.static_method(arg1, arg2, ...);

Alternatively, the API java.callStaticMethod can be used as follows:

java.callStaticMethod('class_name', 'static_method', [arg1, arg2, ...]);
Accessing static fields

Static fields can be accessed as properties of the constructor function.

c.static_field = 10;
var f = c.static_field;

Alternatively, you can use the following APIs:

  • The API java.getStaticFieldValue can be used to retrieve a static field by passing the class name as the first argument and the field name as the second argument.
    java.getStaticFieldValue('class_name', 'field_name')
  • The API java.setStaticFieldValue can be used to set a static field by passing the class name as the first argument, and the field name as second argument and the value to set as last argument.
    java.setStaticFieldValue('class_name', 'field_name', value)
Accessing inner classes defined by a Java class.

When a Java class defines inner classes, these classes can be accessed as properties of the constructor function that java.import returns. The value returned when such properties are accessed is again another JavaScript constructor function.

var c = java.import('class_name');
var ic = c.ic;
var i = new ic(arg1, arg2, ...);

NOTE: It is possible for a Java class to have a static field, a static method, and an inner class with the same name. In such case, the inner class gets highest priority. Between the field and method, field gets higher priority. When a method is unavailable as a property, then use the API java.callStaticMethod to access the static method. When a field is unavailable as a property, then use the API java.setStaticField or java.getStaticField.

 

Using Java objects

The value returned by calling new on the constructor function returned by java.import is a JavaScript object that represents the underlying Java object. It has properties that represent the following:

  1. Instance methods of the object.
  2. Instance fields of the object.
Invoking instance methods

You can invoke instance methods as follows:

var c = java.import('class_name');
var i = new c(arg1, arg2, ...);
i.instance_method();

Alternatively, the API java.callMethod can be used as follows:

java.callMethod(i, 'instance_method',[arg1,arg2,....]);
Accessing instance fields

You can access the instance fields as follows:

var if = i.instance_field;
i.instance_field = 'abc';

NOTE: In Java a class can have an instance method and instance field with same name. Fields get priority over method. Therefore when a method is shadowed by a field, the method can be invoked using java.callMethod.

Invoking the super method of a class

You can invoke the super method of a class as follows:

var c = java.newClass(native_class_name);
var i = new c();
// call's the overridden function "method()" define in this class "native_class_name"
i.method() 
// call's super class function "method()"
i.supermethod();

NOTE: If a method (or function) of a super class is overridden (or redefined) in a subClass, you must add the super keyword as a prefix to the method name (for example, supermethod()) to access it.

Here is an example for invoking the super method of a class:

//Java Code
public class Animal { // Superclass (parent)
  public void animalSound() {
    System.out.println("The animal makes a sound");
  }
}
//JavaScript code
var c = java.newClass('Dog', 'com.animal.Animal', [], {
    animalSound: function () {
        //this refers Dog object
        this.superanimalSound(); // Call the superclass method
        kony.print("The dog says: bow wow");
    }
});
var i = new c();
i.animalSound();// Call the method on the Dog object
Types

Java to JavaScript

When Java returns a value to JavaScript, or passes a value to a callback, Java values are converted to JavaScript values, as follows:

  • null -> null
  • void -> undefined
  • boolean -> boolean
  • String -> string
  • byte -> Byte object
  • long -> Long object
  • int -> Integer object
  • short -> Short object
  • double -> Double object
  • float -> Float object

Java arrays are converted to JavaScript arrays with individual elements converted, as above.

All other Java objects are wrapped in JavaScript objects. These objects behave as described in Using Java objects.

JavaScript to Java

When invoking Java methods, JavaScript values passed are converted to Java values, as below:

  • null, undefined -> null
  • string -> String object
  • int -> Integer object
  • number - >Double object
  • boolean -> Boolean object
  • JavaScript objects that represent Java objects -> Java objects
  • All other JavaScript Objects - > null

JavaScript arrays are converted to Java object arrays with individual elements converted as above.

When a Java method parameter type is byte, short, long, char, and float (that do not have an equivalent representation in JavaScript), the APIs java.newByte, java.newShort, java.newLong, java.newChar, and java.newFloat can be used to create correct type. Each of these APIs accepts a JavaScript number as argument.

var b = java.newByte (10);

When a Java method parameter type is an array, the API java.newArray can be used to create a Java array. The first argument to java.newArray can be 'byte', 'char', 'short', 'double', 'int', 'boolean' or a class name. The second argument to java.newArray is a JavaScript array with individual elements that belong to the type described by the first argument.

var byteArray = java.newArray(‘byte’, [ java.newByte(1), java.newByte(2), java.newByte(3) ]);

 

Exceptions

When Java throws an exception while performing any of the following operations, an error is thrown in JavaScript. The message property of the error object contains the Java exception in its entirety - exception type, exception message, and stack trace.

  • Import a Java class
  • Create instances of a class
  • Invoke static methods
  • Get/Set static fields (including inner classes)
  • Invoke instance methods
  • Get/Set instance fields
Creating classes

To create a class, use the following API:

java.newClass

This API allows you to extend or implement any Android native, Java class, or interface.

NOTE: This API can only be used from the main thread and JavaScript thread. Do not call it from a worker thread.

Signature

JavaScript: java.newClass(native_class_name)

Input Parameters

native_class_name [String] - Mandatory

Specifies the native class name including the package name.

base_class_name [String] - Mandatory

Specifies the class name from which the new class is extended or inherited.

Interface_name [String] - Mandatory

Specifies the interface name that is implemented by the new class.

Interface_name_to_override [String] - Mandatory

Specifies the interface name that must be overridden or implemented by the new class.

Return Values

Returns the class that is created.

Platform Availability

Available on Android platform.

JavaScript Example

//Sample code
var c = java.newClass('MyRunnable', 'java.lang.Object', [ 'java.lang.Runnable' ], { run: function () { print('hello from thread'); } }); var i = new c(); var Thread = java.import('java.lang.Thread'); var thread = new Thread(i); thread.start();

NOTE: Memory Management: An Instance of a class created using the API java.newClass requires a JavaScript object to operate. This JavaScript object becomes “this” in the JavaScript functions that implement the methods of the class. As such the JavaScript object holds a reference to the Java object (for example, to be able to call super methods) and the Java object holds a reference to the JavaScript object (to be able pass it as “this”), creating a circular reference. Hence it is required to call the API java.unref on an instance of a class created by using java.newClass when the instance is no longer needed. For example, if a class is created to make an HTTP request, when the HTTP request finishes, java.unref needs to be called on “this” in both success and failure callbacks.

Other APIs

The following is an API that must be used in Native Function APIs, Classic only:

java.instanceOf

This API is used to find out if a Java object wrapped in a JavaScript object is an instance of a class.

Signature

JavaScript: java.instanceOf (firstargument, secondargument)

Input Parameters

firstargument [String] - Mandatory

Specifies the JavaScript object.

secondargument [String] - Mandatory

Specifies the class name.

Return Values

Returns true if the passed Java object is an instance of the class else it returns false.

Platform Availability

Available on Android platform.

Threads

In a Quantum Visualizer application, most of a JavaScript execution happens on a separate thread (JavaScript thread). When you need to invoke a Java API that can only be called from the main thread, use the API kony.runOnMainThread. To resume execution back on the JavaScript thread, use the API kony.runOnWorkerThread.

For more information on Threading APIs, click here.

Getting Android activity context

The following is a sample code to get the Android activity context:

var KonyMain = java.import('com.konylabs.android.KonyMain');

var context = KonyMain.getActivityContext();

 

Lifecycle events

The Quantum Visualizer Android UI framework is based on a single Activity model, and all the application forms are rendered in the same KonyMain activity. You need to be notified about KonyMain activity life cycle events in Native Android Implementation and Quantum Fabric APIs. The Quantum Visualizer Android platform helps you register for KonyMain activity life cycle events using the following steps:

  1. Create a class to override the android life cycle methods, by using the java.newClass API.
  2. The Quantum Visualizer Android platform helps you register for KonyMain activity life cycle events by using the following API:

    KonyMain.addActivityLifeCycleListener(KonyActivityLifeCycleListener listener);

  3. You can also unregister for Activity life cycle events using following API.

    KonyMain.removeActivityLifeCycleListener(KonyActivityLifeCycleListener listener)

For more information on Activity lifecycle events, click here.

Code:

public class MyKonyActivityLifeCycleListener extends KonyActivityLifeCycleListener {
@

Override

public void onCreate(Bundle savedInstanceState) {}

@

Override

public void onStart() {}

@

Override

public void onRestart() {}

@

Override

public void onResume() {}

@

Override

public void onPause() {}

@

Override

public void onStop() {}

@

Override

public void onDestroy() {}

@

Override

public void onNewIntent(Intent intent) {}

@

Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {}

}

//Registering listener

KonyActivityLifeCycleListener listener = new MyKonyActivityLifeCycleListener();

KonyMain.addActivityLifeCycleListener(listener); //Unregistering listener when not needed

KonyMain.removeActivityLifeCycleListener(listener);

NFI implementation of listening to LifeCycle Events:

var cls = java.newClass("MyKonyActivityLifeCycleListener",

    "com.konylabs.ffi.KonyActivityLifeCycleListener", [], {
        onCreate: function(savedInstanceState) {
            kony.print("onCreate");
        },
        onStart: function() {
            kony.print("onStart");
        },
        onStop: function() {
            kony.print("onStop");
        },
        onPause: function() {
            kony.print("onPause");
        },
        /* 
    onPause: function () {
      kony.print("onPause");
    }.bind(this), // “this”  usually refers to a native Java class this. 
   Incase , you want to get current Javascript context(this), you can bind that using bind(this).
     */
        onResume: function() {
            kony.print("onResume");
        },
        onDestroy: function() {
            kony.print("onDestroy");
        }
    });
//Registering listener
listener = new cls();
KonyMain = java.import("com.konylabs.android.KonyMain");
//Registering listener
KonyMain.addActivityLifeCycleListener(listener);
/*
//Unregistering listener when not needed
KonyMain.removeActivityLifeCycleListener(listener);
*/
Gradle dependencies to access Kotlin classes

To access Kotlin classes in a Quantum application, you must add the Kotlin dependencies in the build.gradle file. To do so, add the following entries in the gradle entries to suffix field of the Project Settings > Native > Android Mobile/Tablet section.

apply plugin: 'kotlin-android'
buildscript {
ext.kotlin_version = "1.3.61"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

}
}
Invoking static methods in the Kotlin class

In the Kotlin programming language, static methods are defined by using a companion identifier.
The static methods can not be accessed as properties of the constructor function returned by the java.import API.

//MyKotlinClass.kt

package com.temenos.kotlinTest;
class MyClass {
companion object{
fun staticMethodJVM(){
println("Invoke static method from Kotlin");
}
}
}

You can use any of the following two methods to invoke static methods in the Kotlin class By using NFI:

Method 1: By Using @JvmStatic Annotation

You can access static methods from Kotlin code using the same syntax as used in Java. Use the @JvmStatic annotation to define static methods in Kotlin class as follows:

// myKotlinClass.kt

package com.temenos.kotlinTest;
class MyKotlinClass {
companion object{
@JvmStatic
fun staticMethodTesting(){
println("Invoke static method from Kotlin");
}
}
}

//js code
var myClass = java.import("com.temenos.kotlinTest.MyKotlinClass");
var value = myClass.staticMethodTesting();

Method 2 : By using a wrappers java class to access the Kotlin static method

Define a method in the java class to invoke the static method from the Kotlin class.

// myKotlinClass.kt

package com.temenos.kotlinTest;
class MyKotlinClass {
companion object{
@JvmStatic
fun staticMethodTesting(){
println("Invoke static method from Kotlin");
}
}
}

//Java code(myJavaClass.java)
public void InvokeStaticMethodFromKotlinClass(){
System.out.println("Invoking static method in Kotlin Class from Java");
KonyKotlinClass.Companion.staticMethodTesting();
}

//JS Code
var myClass = java.import("com.temenos.kotlinTest.myJavaClass");
var value = myClass.InvokeStaticMethodFromKotlinClass();