JNI实例2---扫描SD卡中mp3文件,native层调用Java自定义的类
2013-02-19 22:27
471 查看
此博客是在研究完《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()等函数。
在Java层的native方法为:
调用该native函数时,传入sd卡目录名称(String类型),函数返回一个Track_Info对象数组。(getTracksArray函数)
在实现这个demo时,遇到如下几个问题:
1.没有很好掌握GetMethodID函数的使用
2.JNI函数签名返回值对应表,函数签名没有很好的掌握,导致花费了不少时间排查bug。
3.使用自定义类,首先要能访问类的构造函数,当时没有调用(init),导致花费了很多时间。
(类容较多,分为两篇博客进行介绍----JNI实例3---扫描SD卡中mp3文件,native函数中使用自定义的类)
在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()等函数。
public class Track_Info implements Serializable{ private String displayName; private long size; private String ext;//后缀名称,eg.mp3 private String filePath; private String parentPath; public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public long getSize() { return size; } public void setSize(long size) { // Log.e("Track_Info.java", "setSize() called in JNI, size = " + size); this.size = size; } public String getExt() { return ext; } public void setExt(String ext) { this.ext = ext; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public String getParentPath() { return parentPath; } public void setParentPath(String parentPath) { this.parentPath = parentPath; } }
在Java层的native方法为:
public native void scanDir(String dirPath); public native String[] getPathArray(String dirPath); public native Track_Info[] getTracksArray(String dirPath);
调用该native函数时,传入sd卡目录名称(String类型),函数返回一个Track_Info对象数组。(getTracksArray函数)
在实现这个demo时,遇到如下几个问题:
1.没有很好掌握GetMethodID函数的使用
2.JNI函数签名返回值对应表,函数签名没有很好的掌握,导致花费了不少时间排查bug。
3.使用自定义类,首先要能访问类的构造函数,当时没有调用(init),导致花费了很多时间。
jclass classTrackInfo = (*env)->FindClass(env,"com/coder80/scaner/Track_Info"); // 获取Track_Info类的构造函数ID jmethodID midInit = (*env)->GetMethodID(env,classTrackInfo,"<init>", "()V"); //构造Track_Info对象 jobject objTrackInfo = (*env)->NewObject(env,classTrackInfo,midInit);
(类容较多,分为两篇博客进行介绍----JNI实例3---扫描SD卡中mp3文件,native函数中使用自定义的类)
相关文章推荐
- JNI实例3---扫描SD卡中mp3文件,native层调用Java自定义的类
- Android下c++调用java实现内置外置sd卡MP3扫描并保存在文件中
- JNI实例1---扫描SD卡中mp3文件
- Android-本地方法与Java相互调用-自定义ProgressBar(锅炉压力监测例子)/NDK-JNI开发实例(七)
- java+JNI 生成包头文件与调用实例
- Android apk安装过程及Java、JNI读取安装包内assets资源文件的两种方法(附源码实例)
- Java调用库文件(JNI)(android对此有所改变)
- 02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
- Java jni调用c函数实例
- JNI 使用总结 (JAVA 调用C语言编写的DLL/SO/SL文件)
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- c++ mk文件出错Jni调用产生java.lang.UnsatisfiedLinkError错误解决方法
- java通过JNI调用C++(VC++6.0) 实例
- Java 客户端向服务端上传mp3文件数据的实例代码
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- jni-使用c代码调用java文件
- Java:vs生成JNI,java调用JNI实例
- java JNI 实例 实现调用c++函数
- Chap5:使用JNI技术实现java程序调用第三方dll(c/c++)文件的功能