QAndroidJniObject Class

Provides APIs to call Java code from C++. More...

Header: #include <QAndroidJniObject>
qmake: QT += androidextras
Since: Qt 5.2

Public Functions

QAndroidJniObject()
QAndroidJniObject(const char *className)
QAndroidJniObject(const char *className, const char *signature, ...)
QAndroidJniObject(jclass clazz)
QAndroidJniObject(jclass clazz, const char *signature, ...)
QAndroidJniObject(int object)
~QAndroidJniObject()
T callMethod(const char *methodName) const
T callMethod(const char *methodName, const char *sig, ...) const
QAndroidJniObject callObjectMethod(const char *methodName) const
QAndroidJniObject callObjectMethod(const char *methodName, const char *signature, ...) const
T getField(const char *fieldName) const
QAndroidJniObject getObjectField(const char *fieldName) const
QAndroidJniObject getObjectField(const char *fieldName, const char *signature) const
bool isValid() const
T object() const
void setField(const char *fieldName, T value)
void setField(const char *fieldName, const char *signature, T value)
QString toString() const
QAndroidJniObject &operator=(T object)

Static Public Members

T callStaticMethod(const char *className, const char *methodName)
T callStaticMethod(const char *className, const char *methodName, const char *signature, ...)
T callStaticMethod(jclass clazz, const char *methodName)
T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...)
QAndroidJniObject callStaticObjectMethod(const char *className, const char *methodName)
QAndroidJniObject callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...)
QAndroidJniObject callStaticObjectMethod(jclass clazz, const char *methodName)
QAndroidJniObject callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...)
QAndroidJniObject fromLocalRef(int localRef)
QAndroidJniObject fromString(const QString &string)
T getStaticField(const char *className, const char *fieldName)
T getStaticField(jclass clazz, const char *fieldName)
QAndroidJniObject getStaticObjectField(const char *className, const char *fieldName)
QAndroidJniObject getStaticObjectField(const char *className, const char *fieldName, const char *signature)
QAndroidJniObject getStaticObjectField(jclass clazz, const char *fieldName)
QAndroidJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *signature)
bool isClassAvailable(const char *className)
void setStaticField(const char *className, const char *fieldName, const char *signature, T value)
void setStaticField(const char *className, const char *fieldName, T value)
void setStaticField(jclass clazz, const char *fieldName, const char *signature, T value)
void setStaticField(jclass clazz, const char *fieldName, T value)
bool operator!=(const QAndroidJniObject &o1, const QAndroidJniObject &o2)
bool operator==(const QAndroidJniObject &o1, const QAndroidJniObject &o2)

Detailed Description

Provides APIs to call Java code from C++.

General Notes

  • Class names needs to contain the fully-qualified class name, for example: "java/lang/String".
  • Method signatures are written as "(Arguments)ReturnType"
  • All object types are returned as a QAndroidJniObject.

Method Signatures

For functions that take no arguments, QAndroidJniObject provides convenience functions that will use the correct signature based on the provided template type. For example:

jint x = QAndroidJniObject::callMethod<jint>("getSize");
QAndroidJniObject::callMethod<void>("touch");

In other cases you will need to supply the signature yourself, and it is important that the signature matches the function you want to call. The signature structure is (A)R, where A is the type of the argument(s) and R is the return type. Array types in the signature must have the [ suffix and the fully-qualified type names must have the L prefix and ; suffix.

The example below demonstrates how to call two different static functions.

// Java class
package org.qtproject.qt5;
class TestClass
{
   static String fromNumber(int x) { ... }
   static String[] stringArray(String s1, String s2) { ... }
}

The signature for the first function is "(I)Ljava/lang/String;"

// C++ code
QAndroidJniObject stringNumber = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/TestClass",
                                                                           "fromNumber"
                                                                           "(I)Ljava/lang/String;",
                                                                           10);

and the signature for the second function is "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"

// C++ code
QAndroidJniObject string1 = QAndroidJniObject::fromString("String1");
QAndroidJniObject string2 = QAndroidJniObject::fromString("String2");
QAndroidJniObject stringArray = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/TestClass",
                                                                          "stringArray"
                                                                          "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"
                                                                           string1.object<jstring>(),
                                                                           string2.object<jstring>());

Handling Java Exception

When calling Java functions that might throw an exception, it is important that you check, handle and clear out the exception before continuing.

Note: It is unsafe to make a JNI call when there are exceptions pending.

void functionException()
{
    QAndroidJniObject myString = QAndroidJniObject::fromString("Hello");
    jchar c = myString.callMethod<jchar>("charAt", "(I)C", 1000);
    QAndroidJniEnvironment env;
    if (env->ExceptionCheck()) {
        // Handle exception here.
        env->ExceptionClear();
    }
}

Java Native Methods

Java native methods makes it possible to call native code from Java, this is done by creating a function declaration in Java and prefixing it with the native keyword. Before a native function can be called from Java, you need to map the Java native function to a native function in your code. Mapping functions can be done by calling the RegisterNatives() function through the JNI environment pointer.

The example below demonstrates how this could be done.

Java implementation:

class FooJavaClass
{
    public static void foo(int x)
    {
        if (x < 100)
            callNativeOne(x);
        else
            callNativeTwo(x);
    }

private static native void callNativeOne(int x);
private static native void callNativeTwo(int x);

}

C++ Implementation:

static void fromJavaOne(JNIEnv *env, jobject thiz, jint x)
{
    Q_UNUSED(env)
    Q_UNUSED(thiz)
    qDebug() << x << "< 100";
}

static void fromJavaTwo(JNIEnv *env, jobject thiz, jint x)
{
    Q_UNUSED(env)
    Q_UNUSED(thiz)
    qDebug() << x << ">= 100";
}

void registerNativeMethods() {
    JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
                               {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};

    QAndroidJniObject javaClass("my/java/project/FooJavaClass");
    QAndroidJniEnvironment env;
    jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
    env->RegisterNatives(objectClass,
                         methods,
                         sizeof(methods) / sizeof(methods[0]));
    env->DeleteLocalRef(objectClass);
}

void foo()
{
    QAndroidJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 10);  // Output: 10 < 100
    QAndroidJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 100); // Output: 100 >= 100
}

The Lifetime of a Java Object

Most objects received from Java will be local references and will only stay valid in the scope you received them. After that, the object becomes eligible for garbage collection. If you want to keep a Java object alive you need to either create a new global reference to the object and release it when you are done, or construct a new QAndroidJniObject and let it manage the lifetime of the Java object.

Note: The QAndroidJniObject does only manage its own references, if you construct a QAndroidJniObject from a global or local reference that reference will not be released by the QAndroidJniObject.

JNI Types

Object Types

TypeSignature
jobjectLjava/lang/Object;
jclassLjava/lang/Class;
jstringLjava/lang/String;
jthrowableLjava/lang/Throwable;
jobjectArray[Ljava/lang/Object;
jarray[<type>
jbooleanArray[Z
jbyteArray[B
jcharArray[C
jshortArray[S
jintArray[I
jlongArray[J
jfloatArray[F
jdoubleArray[D

Primitive Types

TypeSignature
jbooleanZ
jbyteB
jcharC
jshortS
jintI
jlongJ
jfloatF
jdoubleD
Other
TypeSignature
voidV
Custom typeL<fully-qualified-name>;

For more information about JNI see: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html

See also QAndroidJniEnvironment and object().

Member Function Documentation

QAndroidJniObject::QAndroidJniObject()

Constructs an invalid QAndroidJniObject.

See also isValid().

QAndroidJniObject::QAndroidJniObject(const char *className)

Constructs a new QAndroidJniObject by calling the default constructor of className.

...
QAndroidJniObject myJavaString("java/lang/String");
...

QAndroidJniObject::QAndroidJniObject(const char *className, const char *signature, ...)

Constructs a new QAndroidJniObject by calling the constructor of className with signature and arguments.

...
jstring myJStringArg = ...;
QAndroidJniObject myNewJavaString("java/lang/String", "(Ljava/lang/String;)V", myJStringArg);
...

QAndroidJniObject::QAndroidJniObject(jclass clazz)

Constructs a new QAndroidJniObject by calling the default constructor of clazz.

Note: The QAndroidJniObject will create a new reference to the class clazz and releases it again when it is destroyed. References to the class created outside the QAndroidJniObject needs to be managed by the caller.

QAndroidJniObject::QAndroidJniObject(jclass clazz, const char *signature, ...)

Constructs a new QAndroidJniObject from clazz by calling the constructor with signature and arguments.

jclass myClazz = ...;
QAndroidJniObject::QAndroidJniObject(myClazz, "(I)V", 3);

QAndroidJniObject::QAndroidJniObject(int object)

Constructs a new QAndroidJniObject around the Java object object.

Note: The QAndroidJniObject will hold a reference to the Java object object and release it when destroyed. Any references to the Java object object outside QAndroidJniObject needs to be managed by the caller.

See also fromLocalRef().

QAndroidJniObject::~QAndroidJniObject()

Destroys the QAndroidJniObject and releases any references held by the QAndroidJniObject.

T QAndroidJniObject::callMethod(const char *methodName) const

Calls the method methodName and returns the value.

QAndroidJniObject myJavaString = ...;
jint size = myJavaString.callMethod<jint>("length");

T QAndroidJniObject::callMethod(const char *methodName, const char *sig, ...) const

Calls the method methodName with a signature sig and returns the value.

QAndroidJniObject myJavaString = ...;
jint index = myJavaString.callMethod<jint>("indexOf", "(I)I", 0x0051);

QAndroidJniObject QAndroidJniObject::callObjectMethod(const char *methodName) const

Calls the Java objects method methodName and returns a new QAndroidJniObject for the returned Java object.

...
QAndroidJniObject myJavaString1 = ...;
QAndroidJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString");
...

QAndroidJniObject QAndroidJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const

Calls the Java object's method methodName with the signature signature and arguments

QAndroidJniObject myJavaString; ==> "Hello, Java"
QAndroidJniObject mySubstring = myJavaString.callObjectMethod("substring", "(II)Ljava/lang/String;", 7, 10);

[static] T QAndroidJniObject::callStaticMethod(const char *className, const char *methodName)

Calls the static method methodName on class className and returns the value.

jint value = QAndroidJniObject::callStaticMethod<jint>("MyClass", "staticMethod");

[static] T QAndroidJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...)

Calls the static method with methodName with signature on class className with optional arguments.

...
jint a = 2;
jint b = 4;
jint max = QAndroidJniObject::callStaticMethod<jint>("java/lang/Math", "max", "(II)I", a, b);
...

[static] T QAndroidJniObject::callStaticMethod(jclass clazz, const char *methodName)

Calls the static method methodName on clazz and returns the value.

...
jclass javaMathClass = ...; // ("java/lang/Math")
jdouble randNr = QAndroidJniObject::callStaticMethod<jdouble>(javaMathClass, "random");
...

[static] T QAndroidJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...)

Calls the static method methodName with signature on clazz and returns the value.

...
jclass javaMathClass = ...; // ("java/lang/Math")
jint a = 2;
jint b = 4;
jint max = QAndroidJniObject::callStaticMethod<jint>(javaMathClass, "max", "(II)I", a, b);
...

[static] QAndroidJniObject QAndroidJniObject::callStaticObjectMethod(const char *className, const char *methodName)

Calls the static method with methodName on the class className.

QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName");

[static] QAndroidJniObject QAndroidJniObject::callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...)

Calls the static method with methodName and signature on the class className.

QAndroidJniObject thread = QAndroidJniObject::callStaticObjectMethod("java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod("java/lang/String", "valueOf", "(I)Ljava/lang/String;", 10);

[static] QAndroidJniObject QAndroidJniObject::callStaticObjectMethod(jclass clazz, const char *methodName)

Calls the static method with methodName on clazz.

[static] QAndroidJniObject QAndroidJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...)

Calls the static method with methodName and signature on class clazz.

[static] QAndroidJniObject QAndroidJniObject::fromLocalRef(int localRef)

Creates a QAndroidJniObject from the local JNI reference localRef. This function takes ownership of localRef and frees it before returning.

Note: Only call this function with a local JNI reference. For example, most raw JNI calls, through the JNI environment, returns local references to a java object.

jobject localRef = env->GetObjectArrayElement(array, index);
QAndroidJniObject element = QAndroidJniObject::fromLocalRef(localRef);

This function was introduced in Qt 5.7.

[static] QAndroidJniObject QAndroidJniObject::fromString(const QString &string)

Creates a Java string from the QString string and returns a QAndroidJniObject holding that string.

...
QString myQString = "QString";
QAndroidJniObject myJavaString = QAndroidJniObject::fromString(myQString);
...

See also toString().

T QAndroidJniObject::getField(const char *fieldName) const

Retrieves the value of the field fieldName.

QAndroidJniObject volumeControl = ...;
jint fieldValue = volumeControl.getField<jint>("MAX_VOLUME");

QAndroidJniObject QAndroidJniObject::getObjectField(const char *fieldName) const

Retrieves the object of field fieldName.

QAndroidJniObject field = jniObject.getObjectField<jstring>("FIELD_NAME");

QAndroidJniObject QAndroidJniObject::getObjectField(const char *fieldName, const char *signature) const

Retrieves the object from the field with signature and fieldName.

Note: Since Qt 5.3 this function can be used without a template type.

QAndroidJniObject field = jniObject.getObjectField("FIELD_NAME", "Ljava/lang/String;");

[static] T QAndroidJniObject::getStaticField(const char *className, const char *fieldName)

Retrieves the value from the static field fieldName on the class className.

[static] T QAndroidJniObject::getStaticField(jclass clazz, const char *fieldName)

Retrieves the value from the static field fieldName on clazz.

[static] QAndroidJniObject QAndroidJniObject::getStaticObjectField(const char *className, const char *fieldName)

Retrieves the object from the field fieldName on the class className.

QAndroidJniObject jobj = QAndroidJniObject::getStaticObjectField<jstring>("class/with/Fields", "FIELD_NAME");

[static] QAndroidJniObject QAndroidJniObject::getStaticObjectField(const char *className, const char *fieldName, const char *signature)

Retrieves the object from the field with signature and fieldName on class className.

Note: Since Qt 5.3 this function can be used without a template type.

QAndroidJniObject jobj = QAndroidJniObject::getStaticObjectField("class/with/Fields", "FIELD_NAME", "Ljava/lang/String;");

[static] QAndroidJniObject QAndroidJniObject::getStaticObjectField(jclass clazz, const char *fieldName)

Retrieves the object from the field fieldName on clazz.

QAndroidJniObject jobj = QAndroidJniObject::getStaticObjectField<jstring>(clazz, "FIELD_NAME");

[static] QAndroidJniObject QAndroidJniObject::getStaticObjectField(jclass clazz, const char *fieldName, const char *signature)

Retrieves the object from the field with signature and fieldName on clazz.

Note: Since Qt 5.3 this function can be used without a template type.

QAndroidJniObject jobj = QAndroidJniObject::getStaticObjectField(clazz, "FIELD_NAME", "Ljava/lang/String;");

[static] bool QAndroidJniObject::isClassAvailable(const char *className)

Returns true if the Java class className is available.

...
if (QAndroidJniObject::isClassAvailable("java/lang/String")) {
   ...
}
...

bool QAndroidJniObject::isValid() const

Returns true if this instance holds a valid Java object.

...
QAndroidJniObject qjniObject;                        ==> isValid() == false
QAndroidJniObject qjniObject(0)                      ==> isValid() == false
QAndroidJniObject qjniObject("could/not/find/Class") ==> isValid() == false
...

T QAndroidJniObject::object() const

Returns the object held by the QAndroidJniObject as type T.

QAndroidJniObject string = QAndroidJniObject::fromString("Hello, JNI");
jstring jstring = string.object<jstring>();

Note: The returned object is still owned by the QAndroidJniObject. If you want to keep the object valid you should create a new QAndroidJniObject or make a new global reference to the object and free it yourself.

void functionScope()
{
    QString helloString("Hello");
    jstring myJString = 0;
    {
        QAndroidJniObject string = QAndroidJniObject::fromString(helloString);
        myJString = string.object<jstring>();
    }

   // Ops! myJString is no longer valid.
}

Note: Since Qt 5.3 this function can be used without a template type, if the returned type is a jobject.

jobject object = jniObject.object();

void QAndroidJniObject::setField(const char *fieldName, T value)

Sets the value of fieldName to value.

...
QAndroidJniObject obj;
obj.setField<jint>("AN_INT_FIELD", 10);
jstring myString = ...
obj.setField<jstring>("A_STRING_FIELD", myString);
...

void QAndroidJniObject::setField(const char *fieldName, const char *signature, T value)

Sets the value of fieldName with signature to value.

QAndroidJniObject stringArray = ...;
QAndroidJniObject obj = ...;
obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", stringArray.object<jobjectArray>())

[static] void QAndroidJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, T value)

Sets the static field with fieldName and signature to value on class className.

[static] void QAndroidJniObject::setStaticField(const char *className, const char *fieldName, T value)

Sets the value of the static field fieldName in class className to value.

[static] void QAndroidJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value)

Sets the static field with fieldName and signature to value on class clazz.

[static] void QAndroidJniObject::setStaticField(jclass clazz, const char *fieldName, T value)

Sets the static field fieldName of the class clazz to value.

QString QAndroidJniObject::toString() const

Returns a QString with a string representation of the java object. Calling this function on a Java String object is a convenient way of getting the actual string data.

QAndroidJniObject string = ...; //  "Hello Java"
QString qstring = string.toString(); // "Hello Java"

See also fromString().

QAndroidJniObject &QAndroidJniObject::operator=(T object)

Replace the current object with object. The old Java object will be released.

Related Non-Members

bool operator!=(const QAndroidJniObject &o1, const QAndroidJniObject &o2)

Returns true if o1 holds a reference to a different object then o2.

bool operator==(const QAndroidJniObject &o1, const QAndroidJniObject &o2)

Returns true if both objects, o1 and o2, are referencing the same Java object, or if both are NULL. In any other cases false will be returned.

© 2021 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.