Qt 5.4文档翻译:QAndroidJniObject类,QAndroidJniObject Class
提供了一些接口,用于从C++中调用Java 代码。详细说明……
头文件: |
#include <QAndroidJniObject> |
qmake: |
QT += androidextras |
自此版本开始引入: |
Qt 5.2 |
提供了一些接口,用于从C++中调用Java 代码。
•.类名必须是完整的类名,例如:"java/lang/String"。
•.方法名是这样写的:"(Arguments)ReturnType"
•.所有的对象类型都是以QAndroidJniObject对象返回的。
对于那些不要参数的函数,QAndroidJniObject提供了一些便利函数,用来根据妳所提供的模板类型生成正确的方法名签名。例如:
jint x = QAndroidJniObject ::callMethod<jint>("getSize");
QAndroidJniObject ::callMethod<void>("touch");
在其它情况下,妳需要自己提供方法名签名,并且要注意,妳所提供的签名必须与妳要调用的函数相匹配。签名结构是(A)R,其中,A是指参数的类型,R是指返回类型。签名中的数组类型必须带有[前缀(☯:原文是suffix),并且,完整的类型名字中必须带有L前缀和;后缀。
下面代码展示了如何调用两个不同的静态函数。
// Java类
package org.qtproject.qt5;
class TestClass
{
static String fromNumber(int x) { ... }
static String[] stringArray(String s1, String s2) { ... }
}
第一个函数的签名是"(I)Ljava/lang/String;"
// C++代码
QAndroidJniObject stringNumber = QAndroidJniObject :: callStaticObjectMethod ("org/qtproject/qt5/TestClass",
"fromNumber"
"(I)Ljava/lang/String;",
10);
而第二个函数的签名是"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"
// C++代码
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>());
当妳调用那种可能会抛出异常的Java函数时,要注意,检查、处理并且清除异常。
注意:在仍然存在未处理的异常的情况下调用JNI 代码是不安全的。
void functionException()
{
QAndroidJniObject myString = QAndroidJniObject ::fromString("Hello");
jchar c = myString.callMethod<jchar>("charAt", "(I)C", 1000);
if (env->ExceptionCheck()) {
// 在此处处理异常。
env->ExceptionClear();
}
}
Java原生方法可用于从 Java 中调用原生代码,具体做法就是,在Java 中创建一个函数声明,并且加上一个native前缀。在能够从 Java 中调用原生函数之前,妳需要将该Java 原生函数映射到妳自己代码中的某个原生函数。函数的映射,可通过JNI环境指针调用RegisterNatives()函数来实现。
以下代码展示了这一点。
Java实现代码:
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++实现代码:
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");
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
}
从Java 接收到的大部分对象都是本地的引用,因此,只会在妳接收到它们的那个作用域中保持有效。从那之后,该对象就可能会被垃圾回收。如果妳想保持某个Java 对象存活的话,则,妳需要做以下两件事中的一件:创建指向该对象的一个新的全局引用,并在妳做完工作之后释放它;或者,构造一个新的QAndroidJniObject,并让这个东西来管理该Java 对象的生命周期。
注意:QAndroidJniObject只会管理它自己的引用,如果妳从一个全局或本地引用来构造一个QAndroidJniObject的话,则,该引用不会被这个QAndroidJniObject所释放。
类型 |
签名 |
jobject |
L<fully-qualified-name>; |
jclass |
|
jstring |
|
jobjectArray |
[L<fully-qualified-name>; |
jarray |
[<type> |
jbooleanArray |
[Z |
jbyteArray |
[B |
jcharArray |
[C |
jshortArray |
[S |
jintArray |
[I |
jlongArray |
[J |
jfloatArray |
[F |
jdoubleArray |
[D |
类型 |
签名 |
jboolean |
Z |
jbyte |
B |
jchar |
C |
jshort |
S |
jint |
I |
jlong |
J |
jfloat |
F |
jdouble |
D |
类型 |
签名 |
void |
V |
欲了解更多关于JNI 的信息,则访问:http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
参考QAndroidJniEnvironment和object()。
通过调用className的默认构造函数来构造一个新的QAndroidJniObject。
...
QAndroidJniObject myJavaString("java/lang/String");
...
对于类className,以signature签名来调用它的静态方法methodName。
QAndroidJniObject thread = QAndroidJniObject :: callStaticObjectMethod ("java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
QAndroidJniObject string = QAndroidJniObject :: callStaticObjectMethod ("java/lang/String", "valueOf", "(I)Ljava/lang/String;", 10);
从QString string来创建一个Java 字符串,并且返回一个持有该字符串的QAndroidJniObject。
...
QString myQString = "QString";
QAndroidJniObject myJavaString = QAndroidJniObject ::fromString(myQString);
...
参考toString()。
获取名为fieldName的字段的值。
QAndroidJniObject volumeControl = ...;
jint fieldValue = volumeControl.getField<jint>("MAX_VOLUME");
获取名为fieldName的字段对应的对象。
QAndroidJniObject field = jniObject.getObjectField<jstring>("FIELD_NAME");
将此QAndroidJniObject所持有的对象以类型T 的形式返回。
QAndroidJniObject string = QAndroidJniObject :: fromString ("Hello, JNI");
jstring jstring = string.object<jstring>();
注意:所返回的那个对象仍然是由该QAndroidJniObject所拥有。如果妳想让该对象保持有效,则,妳应当创建一个新的QAndroidJniObject,或者创建一个新的指向该对象的全局引用,并且在日后自行释放它。
void functionScope()
{
QString helloString("Hello");
jstring myJString = 0;
{
QAndroidJniObject string = QAndroidJniObject ::fromString(helloString);
myJString = string.object<jstring>();
}
// 呃! myJString 到此处已经无效了。
}
注意:自Qt 5.3开始,如果返回的类型是一个jobject的话,则,使用此函数时可不提供模板类型。
jobject object = jniObject.object();
返回一个QString,它是该java 对象的字符串表示方式。对于一个Java String 对象,调用这个函数,是一种便利地获取其字符串数据的方法。
QAndroidJniObject string = ...; // "Hello Java"
QString qstring = string.toString(); // "Hello Java"
参考fromString()。
汤灿
Your opinionsHxLauncher: Launch Android applications by voice commands