深入理解Android(5)——從MediaScanner分析Android中的JNI,mediascannerjni

來源:互聯網
上載者:User

深入理解Android(5)——從MediaScanner分析Android中的JNI,mediascannerjni

前面幾篇介紹了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    },};
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\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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.