QAndroidJniObject

Qt 5.3之后,新增了 QtAndroid 名字空间,内有下列四个方法:

我的书《Qt on Android核心编程》写作时用的 Qt SDK 版本为 5.2.0(第一个正式支持Android的Qt SDK版本),写作过程中 5.3 发布,书里只是简单介绍了下 QtAndroid 的存在,对上面的几个方法没有做实际研究,从本文开始,我就以 Qt 5.3.1 为基础,来展开介绍 QtAndroid 名字空间以及与其密切相关的 QAndroidJniObject 。

QAndroidJniObject

在介绍 QtAndroid 里面的方法之前,必须要介绍 QAndroidJniObject 这个类。因为要使用 Qt 提供的 JNI 功能编程,离开 QAndroidJniObject 可谓寸步难行。

QAndroidJniObject 属于 androidextras 模块,要使用它,需要在 pro 文件中加入下面的代码:

QT += androidextras androidextras 是从 Qt 5.2 引入的。这个模块内还包括了QAndroidJniEnvironment 类,QAndroidJniEnvironment 代表 JNI 环境,也就是通常我们使用 JNI 编程时的 JNIEnv 。我们使用 Qt 进行 JNI 编程时,构造一个 QAndroidJniEnvironment 对象,即可获得 JNIEnv 指针,可以进一步使用 JNIEnv 的方法来实现特定功能,比如检查 JNI 调用过程中是否发生了异常、清理异常等等。更多的细节请参考 Qt 帮助和 jni.h(JDK中有此头文件,可打开浏览) 。

我们的重头戏是 QAndroidJniObject 。

QAndroidJniObject 是对原始 JNI 类型的封装,代表了一个 Java 对象(类的实例),它提供了很多方法供开发者使用,我把它分为三类:

咱们一个一个来看。

构造 Java 对象

要调用 Java 类库,就需要构造 Java 对象,这是第一步,可能也是最难的一步。不过相信随着本文的介绍,你很快就会清楚如何构造一个对应于 Java 对象的 JNI 对象。

QAndroidJniObject 提供了下列构造函数来创建 JNI 对象:

还有一个静态的方便方法供我们从一个 QString 对象来构造 Java 中的 String 对象:

QAndroidJniObjectfromString(const QString & string)

fromString 不必讲了,简单明了。咱们来看构造函数吧。

构造函数又分了两类,一类是根据 Java 类名和 Java 类构函数签名来创建 JNI 对象;一类是根据已有的 JNI 对象(也可结合 Java 构造函数签名)来创建 QAndroidJniObject 对象。我们再简化之,只看 1 、 2 、 3 ,从 Java 类名来创建 QAndroidJNIObject ,那,第一个构造函数无参数,也不介绍了,剩下就俩了。

使用JNI的两点基础

Java 的全路径类名,是带了包名的。 Java 中的包,可以类比于 C++ 里的 namespace ,一个包里可以包含了多个类,一方面方便将关联的类组织到一起,另一方面也可以避免名字冲突。

我们以 String 类来说明。

String 类在包 java.lang 中,全路径类名为 java.lang.String 。当我们在 C++ 用以字符串方式描述一个 Java 类时,需要把 “.” 替换为 “/” ,如 java.lang.String ,,字符串描述为 “java/lang/String” 。又如 android.content.Intent ,字符串描述为 “android/content/Intent” 。

好啦,这是我们在 Qt 中使用 QAndroidJniObject 进行 JNI 编程的第一个基础。

既然有第一个,就有第二个喽。木错,第二个基础就是方法签名。

关于方法签名,我在《Qt on Android核心编程》一书的 15.2.1 节有详尽介绍,Qt 帮助中检索 QAndroidJniObject 也有介绍,这里我们只简单说明一下。

方法签名的表述形式:(Arguments)ReturnType 。圆括号中是参数列表,紧跟圆括号的是返回值类型。例如“(I)C”的意思就是参数为 int ,返回值为 char 。当一个 Java 方法的参数或返回值类型为对象时,需要使用全路径类名,并且加前缀“L”和后缀“;”。如“(Ljava/lang/String;)Ljava/lang/String;”,表示一个方法的参数类型为 String ,返回值也是 String 。

方法签名就介绍到这里了。详细的参考我的书或者 Qt 帮助。

QAndroidJniObject(const char * className)

参数为 “const char * className” 的构造函数,只根据类名来构造 JNI 对象,调用 className 指定的 Java 类的默认构造函数。

我们明白了如何用字符串描述一个 Java 类,QAndroidJniObject(const char*)这个构造函数就很容易理解了。

举几个例子来看。

Intent 类是 Android 提供的、用于组件间通信的一种机制。通过 Intent ,你可以调用其它的系统功能或第三方提供的功能,比如你可以调用拨打电话的功能,可以显示联系人,也可以调用相机。我们在使用 Intent 时可以指定一个 action ,action 代表你要做的动作,也就是你想干啥;还可以在 Intent 中携带数据给被调用的一方。使用起来非常方便。Intent 的全路径类名为 android.content.Intent 。

我们可以这么构造一个 Intent 对象:

QAndroidJniObject intent("android/content/Intent"); 上面的代码就会调用 Intent 的默认构造函数来构造一个 Intent 对象。

String 类的全路径类名为 java.lang.String ,可以这么构造一个空的 String 对象:

QAndroidJniObject str("java/lang/String"); 值得注意的是,使用QAndroidJniObject(const char * className) 这个构造函数来创建 Java 对象,一定要确保你指定的 Java 类有无参构造函数(即默认构造函数)。QAndroidJniObject(const char * className, const char * signature, …)

这个参数根据类名 className 和 指定签名的构造函数来创建 JNI 对象。

还是以 Intent 为例, Intent 有一个构造函数,原型是:Intent(String action) 。我们就根据这个构造函数来创建 Intent 对象,C++ 代码如下:

QAndroidJniObject action = QAndroidJniObject::fromString("android.settings.SETTINGS");QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", action.object<jstring>()); 在上面的代码中,我们先使用 QAndroidJniObject::fromString 构造了一个 Java 的 String 对象作为我们的 action ,这个 action 会打开 Android 系统设置。当遗忘变成另一种开始,淡了回忆,痛最真实…

QAndroidJniObject

相关文章:

你感兴趣的文章:

标签云: