前面几篇介绍了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 voidandroid_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    },};
J NINativeMethod结构体如下:

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\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_MediaRecorder(env) < 0) {        LOGE("ERROR: MediaRecorder native registration failed\n");        goto bail;    }    if (register_android_media_MediaScanner(env) < 0) {        LOGE("ERROR: MediaScanner native registration failed\n");        goto bail;    }    if (register_android_media_MediaMetadataRetriever(env) < 0) {        LOGE("ERROR: MediaMetadataRetriever native registration failed\n");        goto bail;    }    if (register_android_media_AmrInputStream(env) < 0) {        LOGE("ERROR: AmrInputStream native registration failed\n");        goto bail;    }    if (register_android_media_ResampleInputStream(env) < 0) {        LOGE("ERROR: ResampleInputStream native registration failed\n");        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;}

更多相关文章

  1. 如何将uboot里面的参数传给recovery或kernel
  2. Android应用框架之PackageManagerService
  3. Kivy A to Z -- 如何从Python创建一个基于Binder的Service及如何
  4. Android(安卓)Binder IPC分析
  5. Android操作JNI函数以及复杂对象传递
  6. Android(安卓)NDK——必知必会之Native线程操作及线程同步全面详
  7. android手机信号强度
  8. Android材料设计兼容函数库(Design Support Library)(I)导航视图(Navi
  9. Android准备工作

随机推荐

  1. Android常用控件之FragmentTabHost的使用
  2. 1.1安卓系统架构
  3. Android(安卓)三种动画详解及简单实例
  4. android https 连接建立
  5. android:自定义监听(简单)
  6. Android(安卓)学习之Camera拍照流程
  7. vnc 项目的几点总结
  8. [置顶] android 按钮两次点击事件区分
  9. Android(安卓)Span 的使用
  10. Android(安卓)listview onItemClick事件