JNI实例2---扫描SD卡中mp3文件,native层调用Java自定义的类
此博客是在研究完《Android内核剖析》中2.2章节JNI调用机制后,才完成的。在此非常感谢该书的作者。此书的内容较多,讲述的知识点也比较深入,值得各位Android coder们学习。在Android应用开发时,有时候为了提升程序的效率,需要使用到JNI编程,调用native C代码,协作完成应用的某些功能。 理论讲解JNI接口主要包含两种情况,第一种为从Java中调用C,第二种为从C中调用Java。一. Java访问C Java类中可以定义某些native函数。当Java编译器遇到native函数时,不会关心该函数的具体实现。在程序运行时,调用native方法前,必须将C所生成的lib库装载进来。当调用native时,编译器会向native引擎传递调用者的包名,函数名和参数类型。在产生的C函数中,会包含至少两个参数:JNIEnv指针,指向JVM的对象,可以访问JVM内部的各种对象。第二个参数为jobject,指调用者对象。二. C访问Java 如果C中需要使用Java的某个变量而进行相应的处理,或者C中也想调用Java中的某个函数完成某些功能,那么C就得访问Java。 Java中是没有指针的,C访问Java时只能使用特定的接口,需要将要访问的类名,函数名称和参数传递给Java引擎。其步骤如下: 1.获取Java对象的类 cls = env->GetObjectClass(jobject); env为native函数中的第一个参数,jobject为第二个参数。 2. 获取Java函数的id值 jmethodID mid = env->GetMethodId(cls,"method_name","(Ljava/lang/String;)V"); 该方法第二个参数为Java中的函数名称,第三个参数:Ljava/lang/String表示String类型的参数。
“[Ljava/lang/String;”表示String数组。返回值V代表void. 需要注意的是GetMethodID方法的格式。 jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
JNIEnv这个参数C++中不需要。clazz就是前面得到的jclass,name则是方法名称,sig是方法签名。 3. 找到函数后,开始调用函数 env->CallXXXMethod(jobject,mid,ret); 其中XXX代表函数返回值类型,具体包括Void,Object,Boolean,Byte,Char等…通过以上三步,实现了C中调用Java函数的目标。*************************************************************************************************************************** 另外一个问题:C访问Java类中的变量时如何实现的?其实跟以上的步骤相似,也为三个步骤: 1.获取Java对象 2.获取变量的id值 .jmethodID id = env->GetFiledId(cls,"filed_name”,”I”);第三个参数为变量的类型 3. 获取变量的值 Value = env->GetXXXFiled(env,jobjcet,fid); 这个函数以返回值的方式获取变量值。 为了更好的将上述知识点表述清楚,本博客实现一个简单的demo,力争让大家理解清楚。
应用实例
自定义一个类,该对象用于描述sd卡中mp3音频文件的属性。可以参看我前一篇博客内容(JNI实例1---扫描SD卡中mp3文件)native函数用于遍历MP3文件,之后调用Java的Track_Info类方法,native函数分别调用setDisplayName(),setSize(),setFilePath()等函数。
jclass classTrackInfo = (*env)->FindClass(env,"com/coder80/scaner/Track_Info");// 获取Track_Info类的构造函数IDjmethodID midInit = (*env)->GetMethodID(env,classTrackInfo,"<init>", "()V");//构造Track_Info对象jobject objTrackInfo = (*env)->NewObject(env,classTrackInfo,midInit);
(类容较多,分为两篇博客进行介绍----JNI实例3---扫描SD卡中mp3文件,native函数中使用自定义的类)