首页 > 代码库 > Android-JNI总结(1)

Android-JNI总结(1)

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.声明gMethods(JNINativeMethod是一个java 函数与jni函数一一对应的结构体)

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},
};

1-1.第2个参数方法类型签名的简化


2.注册代码的实际调用:

// This function only registers the native methods, and is called from
// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaScanner(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MediaScanner", gMethods, NELEM(gMethods));
}
3.在android_media_MediaPlayer.cpp中声明方法,并在JNI_OnLoad中绑定,在System.loadLibrary()中调用后自动调用JNI_OnLoad()

>>android_media_MediaPlayer.cpp 声明

extern int register_android_media_MediaScanner(JNIEnv *env);
>>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;
}


3>>对应类型转换



4>>JNIEnv (与线程相关的一个JNI环境结构体)


1)JNIEnv操作jobject相当于操作jfieldID和jmethodID


获取methodID


调用mEnv操作(Call<Type>Method) methodID


获取fieldID




5>>垃圾回收机制  变量生命周期  (全局引用 局部引用全局引用)

全局引用:NewGlobalRef声明mClient(env->NewGlobalRef(client))

DeleteGlobalRef 销毁mEnv->DeleteGlobalRef(mClient);

全局引用:特殊的全局引用使用前调用JNIEnv->IsSameOject判断是否被回收


6>>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();



Android-JNI总结(1)