1>>JNI结构 (Java代码>JNI代码>C/C++代码)
2>>一个MediaScanner调用例子
1.java层:(加载函数库 库名由.mk文件配置)
public class MediaScanner { static { System.loadLibrary("media_jni");//加载类库 native_init();//调用jni层代码 } private static native final void native_init(); }2 .jni层:静态注册(函数名对包名_类名_方法名)
static void android_media_MediaScanner_native_init(JNIEnv *env)//jni代码实现 { jclass clazz; clazz = env->FindClass("android/media/MediaScanner"); if (clazz == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner"); return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); if (fields.context == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext"); return; } }
***************************************静态注册***********************************
java文件:
/** * @author Lean @date:2014-11-29 */ public class GetStr { static{ System.loadLibrary("JNISample"); } public static native String testGet(); }
>>获取jni的.h代码文件
生成.h文件,调用javah -jni packagename.classname
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnisample_GetStr */ #ifndef _Included_com_example_jnisample_GetStr #define _Included_com_example_jnisample_GetStr #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnisample_GetStr * Method: testGet * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_jnisample_GetStr_testGet (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
>>生成.so对应
书写jni文件,复制com_example_jnisample_GetStr.h文件函数名到JNISample.cpp 如下:
#include <jni.h> #include "com_example_jnisample_GetStr.h" extern "C" { #endif /* * Class: com_example_jnisample_GetStr * Method: testGet * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_jnisample_GetStr_testGet (JNIEnv *env, jclass){ return env->NewStringUTF("hello"); } #ifdef __cplusplus }至此 ,可以通过调用java文件调用到jni层,并在jni 层调用具体的c/c++代码。
***************************************动态注册***********************************
1.MediaScanner的动态注册在执行System.loadLibrary("")后,系统统一调用android_media_MediaPlayer的JNI_OnLoad()方法;
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (register_android_media_MediaScanner(env) < 0) { LOGE("ERROR: MediaScanner native registration failed\n"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; bail: return result; }
int register_android_media_MediaScanner(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, "android/media/MediaScanner", gMethods, NELEM(gMethods)); }
static JNINativeMethod gMethods[] = { {"processDirectory", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", (void *)android_media_MediaScanner_processDirectory}, {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", (void *)android_media_MediaScanner_processFile}, {"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale}, {"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt}, {"native_init", "()V", (void *)android_media_MediaScanner_native_init}, {"native_setup", "()V", (void *)android_media_MediaScanner_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize}, };
*.gMethods中签名中方法类型签名的简化
*.java代码对应的jni对象类型
*.JNIEnv*表示jni环境与线程绑定的变量.
如果从方法里面获取JNIEnv* 则表示的是当前的变量,如果从后台服务获取,则需要从JNI_OnLoad()中的参数
JavaVm* vm获取 并调用AttachCurrentThread()。在后台线程退出前,必须调用DetachCurrenThread()。
*.JNIEnv操作jobject相当于操作jfieldID和jmethodID
1.获取methodID,后调用mEnv操作(Call<Type>Method) methodID
2.获取fieldID 后 ,调用set<type>Field() 或者set<type>Field()
*.垃圾回收机制 变量生命周期 (全局引用 局部引用弱全局引用)
全局引用:NewGlobalRef声明mClient(env->NewGlobalRef(client))
DeleteGlobalRef 销毁mEnv->DeleteGlobalRef(mClient);
弱全局引用:特殊的全局引用使用前调用JNIEnv->IsSameOject判断是否被回收
*.jstring java中String 对象在jni 中的影射
本地字符串转JAVA 的String
Unicode:JNIEnv->NewString();
UTF-8:JNIEnv->NewStringUTF();
JAVA 的String转本地字符串
Unicode:JNIEnv->GetStringCharas();
UTF-8:JNIEnv->GetStringUTFCharas();
释放资源:
Unicode:JNIEnv->ReleaseStringCharas();
UTF-8:JNIEnv->ReleaseStringUTFCharas();