Android之ndk
来源:互联网 发布:网络厂商排名 编辑:程序博客网 时间:2024/06/16 22:20
一、类的相关操作
1. jclass FindClass(JNIEnv *env, const char *name); 查找类
该函数可能做过Java开发的不会陌生,这个是JNI层的实现,需要注意的是第二个参数为const char*类型的,我们如果从Java从层传入unicode编码的jstring类型需要使用GetStringUTFChars函数转换成utf8的const char*,如果成功返回这个Java类的对象jclass,相关的异常可能有
(1. ClassFormatError 类的数据格式无效
(2. ClassCircularityError 该类或接口是自身的超类或超接口
(3. NoClassDefFoundError 没有找到指定名称的类或接口
(4. OOM内存不足错误,即OutOfMemoryError
2. jclass GetSuperclass(JNIEnv *env, jclass clazz); 获取父类或者说超类
该函数的第二个参数为jclass类,我们调用时传入的是子类,否则返回将是NULL
3. jboolean IsAssignableFrom(JNIEnv *env, jclass clazz1,jclass clazz2); 判断class1对象能否安全的强制转换为class2对象
如果可以将返回 JNI_TRUE,JNI_TRUE的定义值为1,否则返回JNI_FALSE即0 ,这里Android123详细说明下哪些情况可能返回真:
(1 这两个类参数引用同一个 Java 类
(2 第一个类是第二个类的子类
(3 第二个类是第一个类的某个接口
4. jclass GetObjectClass(JNIEnv *env, jobject obj); 通过对象获取这个类
该函数比较简单,唯一注意的是对象不能为NULL,否则获取的class肯定返回也为NULL。
5. jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz); 判断对象是否为某个类的实例
这个函数是JNI层的实现,相信大家都不陌生,Android开发网提醒大家需要注意的是返回值可能产生异议,就是如果传入的第二个参数为NULL对象,NULL对象可以强制转换为各种类,所以这种情况也将会返回JNI_TRUE,所以一定判断传入的对象是否为空。
6. jboolean IsSameObject(JNIEnv *env, jobject ref1,jobject ref2); 判断两个对象是否引用同一个类
需要注意的是如果两个对象均为空,返回的值也会是JNI_TRUE所以使用时判断对象为空。
二、调用Java方法
首先说下有关签名sig相关的比如 "Ljava/lang/String;"
1. jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 获取一个Java方法的ID
这个函数将返回非静态类或接口实例方法的方法 ID。这个方法可以是某个clazz 的超类中定义,也可从clazz 继承,最后一个参数为签名,最后两个参数是const char*类型,是utf8类型。需要注意的是Android123提醒大家执行GetMethodID()函数将导致未初始化的类初始化,如果要获得构造函数的方法ID,使用 <init> 作为方法名,同时将 void (V) 作为返回类型,如果找不到指定的ID将返回NULL,同时异常可能有:
(1 NoSuchMethodError 找不到指定的Java方法。
(2 ExceptionInInitializerError 如果由于异常而导致类初始化程序失败
(3 OutOfMemoryError 内存不足
2 . NativeType CallXXXMethod (JNIEnv *env, jobject obj,jmethodID methodID, va_list args); 调用XXX类型的Java方法
执行Java类中某个方法,需要注意的是这个里的java类是非静态的,由于Java的方法的类型比较多,所以该函数可能有以下几种形式,如CallObjectMethod,CallBooleanMethod,CallByteMethod,CallCharMethod,CallShortMethod,CallIntMethod,CallLongMethod,CallFloatMethod,CallDoubleMethod和CallVoidMethod,需要注意的是,该函数的第三个参数为通过GetMethodID函数获取的方法ID,最后一个参数为这个方法的参数表,最后的va_list宏可以通过搜索获取具体的使用方法,这里Android开发网不再赘述。
3.NativeType CallNonvirtualXXXMethod (JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, jvalue *args);
CallNonvirtualXXXMethod函数和上面的CallXXXMethod 不同之处是多了一个jclass参数,CallXXXMethod是根据对象来调用方法,而CallNonvirtualXXXMethod是根据类的实例调用,区别在这点。
上面的三个均为非静态类的获取,执行调用,需要实例化这个类才可以执行,下面的为静态调用。
4. jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
5. NativeType CallStaticXXXMethod(JNIEnv *env, jclass clazz,jmethodID methodID, ...);
三、访问Java对象的域
Java对象的域或者说字段、属性(Field) 类似方法的执行
1. jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 获取实例对象的域ID
需要注意的是,非静态的实例化后的对象,可能产生的异常有
(1 NoSuchFieldError 找不到指定的域
(2 ExceptionInInitializerError 因为异常而导致类初始化失败
(3 OutOfMemoryError内存不足。
2. NativeType GetXXXField(JNIEnv *env, jobject obj,jfieldID fieldID);
类似GetXXXMethod函数,可能有的类型有 GetObjectField,GetBooleanField,GetByteField,GetCharField,GetShortField,GetIntField,GetLongField,GetFloatField,GetDoubleField。
3. void SetXXXField(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
Java的域可以赋值的,可能有的类型有 SetObjectField,SetBooleanField,SetByteField,SetCharField,SetShortField,SetIntField,SetLongField,SetFloatField,SetDoubleField。
上面3种情况均为非静态对象的域,对于不需要实例化对象的域,可以直接使用下面的。
4. jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
5. NativeType GetStaticXXXField(JNIEnv *env, jclass clazz,jfieldID fieldID);
6. void SetStaticXXXField(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
四、实例代码
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <jni.h> #include <android/log.h> #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__)) /**********传输整数************* */ JNIEXPORT void JNICALL Java_com_nan_callback_MyCallbackActivity_callJNIInt( JNIEnv* env, jobject obj , jint i) { //找到java中的类 jclass cls = (*env)->FindClass(env, "com/nan/callback/MyCallbackActivity"); //再找类中的方法 jmethodID mid = (*env)->GetMethodID(env, cls, "callbackInt", "(I)V"); if (mid == NULL) { LOGI("int error"); return; } //打印接收到的数据 LOGI("from java int: %d",i); //回调java中的方法 (*env)->CallVoidMethod(env, obj, mid ,i); } /********传输字符串************* */ JNIEXPORT void JNICALL Java_com_nan_callback_MyCallbackActivity_callJNIString( JNIEnv* env, jobject obj , jstring s) { //找到java中的类 jclass cls = (*env)->FindClass(env, "com/nan/callback/MyCallbackActivity"); //再找类中的方法 jmethodID mid = (*env)->GetMethodID(env, cls, "callbackString", "(Ljava/lang/String;)V"); if (mid == NULL) { LOGI("string error"); return; } const char *ch; //获取由java传过来的字符串 ch = (*env)->GetStringUTFChars(env, s, NULL); //打印 LOGI("from java string: %s",ch); (*env)->ReleaseStringUTFChars(env, s, ch); //回调java中的方法 (*env)->CallVoidMethod(env, obj, mid ,(*env)->NewStringUTF(env,"你好haha")); } /********传输数组(byte[])************* */ JNIEXPORT void JNICALL Java_com_nan_callback_MyCallbackActivity_callJNIByte( JNIEnv* env, jobject obj , jbyteArray b) { //找到java中的类 jclass cls = (*env)->FindClass(env, "com/nan/callback/MyCallbackActivity"); //再找类中的方法 jmethodID mid = (*env)->GetMethodID(env, cls, "callbackByte", "([B)V"); if (mid == NULL) { LOGI("byte[] error"); return; } //获取数组长度 jsize length = (*env)->GetArrayLength(env,b); LOGI("length: %d",length); //获取接收到的数据 int i; jbyte* p = (*env)->GetByteArrayElements(env,b,NULL); //打印 for(i=0;i<length;i++) { LOGI("%d",p[i]); } char c[5]; c[0] = 1;c[1] = 2;c[2] = 3;c[3] = 4;c[4] = 5; //构造数组 jbyteArray carr = (*env)->NewByteArray(env,length); (*env)->SetByteArrayRegion(env,carr,0,length,c); //回调java中的方法 (*env)->CallVoidMethod(env, obj, mid ,carr); }
从C层调用Java层的方法原理还是通过反射机制。
Java 方法映射到C中的签名
如:jmethodID md = (*env)->GetMethodID(env,class_CommonMethod,"print","(ILjava/lang/String;)V");
观察下面四个方法对应的签名
public void test(){} ()V
public void test1(int i){} (I)V
public int test2(){ return 1;} ()I
public int test3(int i) { return i;} (I)I
由此可以看出:签名是由两部分组成,"()" 里面代表的是方法的参数,后面外面的部分代表的是该方法的返回值
关于这两部分的定义其实又有分 基本数据类型 和 引用数据类型
基本数据类型对应关系如表:
引用数据类型:比较麻烦点,以“L”开头,以“;”结束,中间对应的是该类型的路径
如:String : Ljava/lang/String;
Object: Ljava/lang/Object;
自定义类 Cat 对应 package com.duicky;
Cat : Lcom/duicky/Cat;
数组表示: 数组表示的时候以“[” 为标志,一个“[”表示一维数组
如:int [] :[I
Long[][] : [[J
Object[][][] : [[[Ljava/lang/Object;
我们可以使用jdk自带的工具javap来查看某个类下面所有方法的签名
cmd中输入命令 : javap -s 类名
最后有关Android JNI最后的终极内容,Android开发网主要说明下JVM和JNI的全局引用相关内容,比如本地全局引用LocalGlobalRef,弱全局引用WeakGlobalRef,JNI中线程处理的高级方法比如AttachCurrentThread,以及JNI中的NIO的相关特性将在明天继续讲解,更多的有关Android平台NDK开发内容可以查看我们 Android NDK开发技巧系列文章。
文章引自:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/18/2143977.html
文章引自:http://www.android123.com.cn/androidkaifa/683.html
- Android NDK之Hello NDK
- android之NDK开发
- android ndk之常用命令
- android ndk之常用命令
- Android之NDK开发
- android NDK之Log
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- Android之NDK开发
- android之NDK
- Android之NDK开发
- Android ndk 之二
- Android之NDK开发
- POJ 1125 Stockbroker Grapevine(DP)
- Hdu 2196 题解
- 微博用户相似度分析
- 使用Zlib库进行文件的压缩和解压
- Android - 确认ImageView的图片是否加载成功
- Android之ndk
- 用JAVA 实现“生产者-消费者”问题
- 不用修改任何核心文件,实现dede模板pc和手机访问的页面制作教程
- 计算机图形学_复习整理(3)
- Delphi xe7并行编程快速入门
- Exp-00009错误解決
- 深入分析为Visual Assist设置快捷键的方法
- POJ 1157 LITTLE SHOP OF FLOWERS(DP)
- VS2010上MFC项目出现 \VC\bin\rcdll.dll 无法找到资源编译器