zoukankan      html  css  js  c++  java
  • 深入理解Android(5)——从MediaScanner分析Android中的JNI

    前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结。

    一、通向两个不同世界的桥梁

    在前面我们说过,JNI就像一个桥梁,将Java和Native世界紧密的联系在了一起,在Android平台上如果没有Native层的支持我们的系统寸步难行,甚至Java中的虚拟机也是通过Native实现的。


    二、MediaScanner类的简单介绍

    MediaScannerr完成android中的多媒体文件的扫描工作。例如,mediascanner扫描系统内存和SD卡文件之后,会将扫描的结果加载在数据库中,在Music这个应用程序中看到的显示在activity 的list列表上歌曲专辑名,流派,歌曲时长等信息,都是扫描后的结果放在数据库中,最后读到的数据库中的信息。

    MediaScanner这项功能使用到的三种android的基本组件:

    1、MediaScannerService(从Service中派生),完成扫描任务,并将扫描结果放入到媒体数据库中。

    2、MediaProvider(ContentProvider派生),针对媒体库进行相关操作请求,一般情况就是写,删,查,更操作。

    3、MediaScannerReceiver接收外界的扫描请求。


    三、MediaScanner注册分析

    打开MediaScnner.java可以看到

        static {
            System.loadLibrary("media_jni");
            native_init();
        }
    在这里加载了动态链接库,再调用了native_init()方法

    private static native final void native_init();
    打开android_media_MediaScanner.cpp可以看到native_init()的实现

    // This function gets a field ID, which in turn causes class initialization.
    // It is called from a static block in MediaScanner, which won't run until the
    // first time an instance of this class is used.
    static void
    android_media_MediaScanner_native_init(JNIEnv *env)
    {
        LOGV("native_init");
        jclass clazz = env->FindClass(kClassMediaScanner);
        if (clazz == NULL) {
            return;
        }
    
        fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
        if (fields.context == NULL) {
            return;
        }
    }
    上面的这种注册方式是静态注册,其实还有一种动态的注册方式

    Java native函数和JNI函数是一一对应的,所以在JNI中,是通过JNINativeMethoid结构来记录这种关系的。下面就是android_media_MediaScanner.cpp中的动态注册表。

    static JNINativeMethod gMethods[] = {
        {
            "processDirectory",
            "(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
        },
    };
    JNINativeMethod结构体如下:

    type struct{
        const char* name;
        const char* signature;
        void* fnPtr;
    }JNINativeMethod;
    第一个属性是Java中native函数的名字

    第二个属性是参数和返回类型的签名

    第三个属性是Native对应函数名字

    AndroidRunTime类提供了一个registerNativeMethods函数来完成注册工作,实现如下:

    /*
     * Register native methods using JNI.
     */
    /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
        const char* className, const JNINativeMethod* gMethods, int numMethods)
    {
        return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    }
    jniRegisterNativeMethods是Android平台提供的一个帮助函数。

    在实际的应用中只用两个函数就可以完成动态注册工作。

    jclass clazz = (*env)->FindClass(env, className);
    (*env)->RegisterNatives(env, clazz, gMethods, numMethods);
    当Java层通过System.loadLibrary加装玩JNI动态库后,紧接着会查找该库中一个叫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
    ");
            goto bail;
        }
        assert(env != NULL);
    
        if (register_android_media_MediaPlayer(env) < 0) {
            LOGE("ERROR: MediaPlayer native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaRecorder(env) < 0) {
            LOGE("ERROR: MediaRecorder native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaScanner(env) < 0) {
            LOGE("ERROR: MediaScanner native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaMetadataRetriever(env) < 0) {
            LOGE("ERROR: MediaMetadataRetriever native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_AmrInputStream(env) < 0) {
            LOGE("ERROR: AmrInputStream native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_ResampleInputStream(env) < 0) {
            LOGE("ERROR: ResampleInputStream native registration failed
    ");
            goto bail;
        }
    
        if (register_android_media_MediaProfiles(env) < 0) {
            LOGE("ERROR: MediaProfiles native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpDatabase(env) < 0) {
            LOGE("ERROR: MtpDatabase native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpDevice(env) < 0) {
            LOGE("ERROR: MtpDevice native registration failed");
            goto bail;
        }
    
        if (register_android_mtp_MtpServer(env) < 0) {
            LOGE("ERROR: MtpServer native registration failed");
            goto bail;
        }
    
        /* success -- return valid version number */
        result = JNI_VERSION_1_4;
    
    bail:
        return result;
    }

  • 相关阅读:
    免费的视频、音频转文本
    Errors are values
    Codebase Refactoring (with help from Go)
    Golang中的坑二
    Cleaner, more elegant, and wrong(msdn blog)
    Cleaner, more elegant, and wrong(翻译)
    Cleaner, more elegant, and harder to recognize(翻译)
    vue控制父子组件渲染顺序
    computed 和 watch 组合使用,监听数据全局数据状态
    webstorm破解方法
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468557.html
Copyright © 2011-2022 走看看