QAndroidJniObject Class

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

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

This class was introduced in Qt 5.2.

Public Functions

Detailed Description

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()

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