Android JNI 分析

 实例参考:

MediaScanner.java  (frameworks/base/media/java/android/media/MediaScanner.java)

android_media_MediaScanner.cpp (frameworks/base/media/jni/android_media_MediaScanner.cpp

 

 1,  JNI 的调用关系:

                 Java  ------------------------  JNI       ------------------------       Native 

        以 MediaScanner 为实例:

         MediaScanner --------- libmedia_jni.so -------------     libmedia.so

 

2,  加载JNI 库:

public class MediaScanner
{
    static {
        System.loadLibrary("media_jni");
        native_init();
    }
    ....
}

 

    在调用Native的函数之前,需加载JNI库,一般在类的static中加载,调用System.loadLibrary();

   在加载了相应的JNI库之后,若要使用相应的native函数,只需使用native声明需要被调用的函数:

    private native void processDirectory(String path, String extensions, MediaScannerClient client);
    private native void processFile(String path, String mimeType, MediaScannerClient client);
    public native void setLocale(String locale);

 

3, JNI层分析:

   如Java层中调用native的processFile()在JNI层的实现:

static void
android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client)
{
    MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);

    if (path == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

    const char *pathStr = env->GetStringUTFChars(path, NULL);
    if (pathStr == NULL) {  // Out of memory
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }
    const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
    if (mimeType && mimeTypeStr == NULL) {  // Out of memory
        env->ReleaseStringUTFChars(path, pathStr);
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

    MyMediaScannerClient myClient(env, client);
    mp->processFile(pathStr, mimeTypeStr, myClient);
    env->ReleaseStringUTFChars(path, pathStr);
    if (mimeType) {
        env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
    }
}


注册 JNINativeMethod:

static JNINativeMethod gMethods[] = {
{
    {"processFile",       
     "(Ljava/lang/String;Ljava/lang/String;
                Landroid/media/MediaScannerClient;)V",
   (void *)android_media_MediaScanner_processFile},
};

 

调用 registerNativeMethods() 函数注册:

// 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));
}

补充: Java中proceedFile是如何默认找到 JNI Native中的 processFile:

          由于MediaScanner.java位于android.media包中,因此processFile的全路径名应该是:android.media.MediaScanner.processFile  =====> android_media_MediaScanner.cpp 的路径名   -----这样就会形成一个匹配。

4,   JNI 动态注册:

        若是使用registerNativeMethods()动态注册JNI的,  在上层JAVA调用System.loadLibrary加载完JNI动态库后,接着会查找JNI动态库中的JNI_OnLoad()函数,然后在该函数中完成动态注册的工作:

extern int register_android_media_MediaScanner(JNIEnv *env);

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_MediaPlayer(env) < 0) {
        LOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }

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


参考上述的实例,可以自己实现一个JAVA 调用JNI的例子。

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值