JNI 常用的JNI操作Demo 良心作品

来源:互联网 发布:mac打开照片 编辑:程序博客网 时间:2024/05/24 06:38

感触:楼主学习JNI有几天了,发现网上点击率非常高的博客里面错误百出,让我这个NDK小白费了很多功夫才把一个个案例跑起来,决定自己写一篇博客记录一下也能给需要的人一些帮助。奋斗

JNI 最常用的Signautre的查找方式:

AS->Terminal->javap -s -p [类的包地址]

如果是AS项目中的类需要cd 到app\build\intermediates\classes\debug下再执行上面的代码。

如果是JDK的类就直接整。

eg:javap -s -p java.util.ArrayList

-------------结果-------------------------------

  public java.util.ArrayList(int);
    Signature: (I)V
  public java.util.ArrayList();
    Signature: ()V
  public java.util.ArrayList(java.util.Collection<? extends E>);
    Signature: (Ljava/util/Collection;)V

  public boolean add(E);
    Signature: (Ljava/lang/Object;)Z

-------------------------------------------------------------------------------

下面开始常用案例的总结:(版本:AS1.5 NDK r10e)

1.Native返回ArrayList<E>

需要用到的方法:

1.FindClass:传入一个Class描述符,JVM会从classpath路径下搜索该类,并返回jclass类型(用于存储Class对象的引用)。注意ClassMethod的Class描述符为com/study/jnilearn/ClassMethod,要将.(点)全部换成/(反斜杠)

最重要的是在这个路径下不要加L和分号否则AS必然报错!

2.GetMethodID:调用GetMethodID函数,从ArrayList类中获取构造函数方法ID,返回jmethodID类型(用于存储方法的引用)。实参clazz是第一步找到的jclass对象,实参"callStaticMethod"为方法名称,实参“(Ljava/lang/String;I)V”为方法的签名。

eg:

<span style="font-size:18px;">mid_instance = (env)->GetMethodID( clazz, "callInstanceMethod","(Ljava/lang/String;I)V"); 此方法对应:private void callInstanceMethod(String str, int i) </span>

3.NewObject:构造新的 Java 对象。方法 ID指示应调用的构造函数方法。

4.NewStringUTF:通过调用NewStringUTF函数,会构建一个新的java.lang.String字符串对象。这个新创建的字符串会自动转换成Java支持的Unicode编码。如果JVM不能为构造java.lang.String分配足够的内存,NewStringUTF会抛出一个OutOfMemoryError异常,并返回NULL。在这个例子中我们不必检查它的返回值,如果NewStringUTF创建java.lang.String失败,OutOfMemoryError这个异常会被在Sample.main方法中抛出。如果NewStringUTF创建java.lang.String成功,则返回一个JNI引用,这个引用指向新创建的java.lang.String对象。

5.CallXXXMethod:

JVM针对所有数据类型的返回值都定义了相关的函数,JNI提供了一系列不同返回值的函数,如:CallIntMethod、CallFloatMethod、CallShortMethod、CallObjectMethod等,分别表示调用返回值为int、float、short、Object类型的函数,引用类型统一调用CallObjectMethod函数。另外,每种返回值类型的函数都提供了接收3种实参类型的实现:CallXXXMethod(env, clazz, methodID, ...),CallXXXMethodV(env, clazz, methodID, va_list args),CallXXXMethodA(env, clazz, methodID, const jvalue *args),分别表示:接收可变参数列表、接收va_list作为实参和接收const jvalue*为实参。

献上作者编译好能运行的代码

Native层:

JNIEXPORT jobject JNICALLJava_c_example_com_jni_jnidemo_getPeopleInfo(JNIEnv *env, jclass cls, jobject students) {    //获得ArrayList类引用 记住FindClass千万不能后面跟分号。。。    jclass list_cls = env->FindClass("java/util/ArrayList");    //获得得构造函数Id    jmethodID list_costruct = env->GetMethodID(list_cls, "<init>", "()V");    //创建一个Arraylist集合对象    jobject list_obj = env->NewObject(list_cls, list_costruct);    if(list_cls==NULL)        return NULL;    //获得add方法 后面的签名    jmethodID list_add  = env->GetMethodID(list_cls,"add","(Ljava/lang/Object;)Z");    //获取People类    jclass peo_cls = env->FindClass("c/example/com/jni/People");    //获取People类的构造函数 参数:String Student    jmethodID peo_costruct = env->GetMethodID(peo_cls , "<init>", "(Ljava/lang/String;Lc/example/com/jni/Student;)V");    //获取Student类    jclass stu_cls=env->FindClass("c/example/com/jni/Student");    //获取Student构造函数    jmethodID stu_construct=env->GetMethodID(stu_cls, "<init>", "(Ljava/lang/String;I)V");    for(int i = 0 ; i < 3 ; i++)    {        //构造java中的name        jstring str = env->NewStringUTF("ssssss");        //构造一个Student对象        jobject stu_obj = env->NewObject(stu_cls, stu_construct, str, 11);        //构造一个People对象        jobject peo_obj = env->NewObject(peo_cls , peo_costruct , str,stu_obj);        //执行Arraylist类实例的add方法,添加一个People对象        env->CallBooleanMethod(list_obj , list_add , peo_obj);    }    return list_obj;}

Java层:

  public static native ArrayList<People> getPeopleInfo(ArrayList<Student> students);

Bean层:

public class People {    private String name;    private Student student;    public People(){}    public People(String name, Student student) {        this.name = name;        this.student = student;    }

public class Student {    private String name;    private int age;    public Student(){}    public Student(String name, int age) {        this.name = name;        this.age = age;    }}
常用签名:

类型           相应的签名  
boolean        Z  
byte           B  
char           C  
short          S  
int            I  
long           J  
float          F  
double         D  
void           V  
object         L用/分隔包的完整类名:   Ljava/lang/String; 
Array          [签名          [I      [Ljava/lang/Object;  
Method         (参数1类型签名 参数2类型签名···)返回值类型签名 
特别注意:Object后面一定有分号(;)结束的,多个对象参数中间也用分号(;)来分隔 



0 0
原创粉丝点击