💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
现在分析MS的JNI层。在Java层中,有三个函数涉及JNI层,它们是: - native_init,这个函数由MediaScanner类的static块调用。 - native_setup,这个函数由MediaScanner的构造函数调用。 - processDirectory,这个函数由MS扫描文件夹时调用。 分别来分析它们。 1. native_init函数的分析 下面是native_init对应的JNI函数,其代码如下所示: **android_media_MediaScanner.cpp** ~~~ static void android_media_MediaScanner_native_init(JNIEnv*env) { jclass clazz; clazz =env->FindClass("android/media/MediaScanner"); //取得Java中MS类的mNativeContext信息。待会创建Native对象的指针会保存 //到JavaMS对象的mNativeContext变量中。 fields.context = env->GetFieldID(clazz,"mNativeContext", "I"); ...... } ~~~ native_init函数没什么新意,这种把Native对象的指针保存到Java对象中的做法,已经屡见不鲜。下面看第二个函数native_setup。 2. native_setup函数的分析 native_setup对应的JNI函数如下所示: **android_media_MediaScanner.cpp** ~~~ android_media_MediaScanner_native_setup(JNIEnv*env, jobject thiz) { //创建Native层的MediaScanner对象 MediaScanner*mp = createMediaScanner(); ...... //把mp的指针保存到Java MS对象的mNativeContext中去 env->SetIntField(thiz,fields.context, (int)mp); } //下面的createMediaScanner这个函数将创建一个Native的MS对象 static MediaScanner *createMediaScanner() { #if BUILD_WITH_FULL_STAGEFRIGHT charvalue[PROPERTY_VALUE_MAX]; if(property_get("media.stagefright.enable-scan", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value,"true"))) { return new StagefrightMediaScanner; //使用Stagefright的MS } #endif #ifndef NO_OPENCORE returnnew PVMediaScanner(); //使用Opencore的MS,我们会分析这个 #endif returnNULL; } ~~~ native_setup函数将创建一个Native层的MS对象,不过可惜的是,它使用的还是Opencore提供的PVMediaScanner,所以后面还不可避免地会和Opencore“正面交锋”。 4. processDirectory函数的分析 看processDirectories函数,它对应的JNI函数代码如下所示: **android_media_MediaScanner.cpp** ~~~ android_media_MediaScanner_processDirectory(JNIEnv*env, jobject thiz, jstring path, jstring extensions, jobject client) { /* 注意上面传入的参数,path为目标文件夹的路径,extensions为MS支持的媒体文件后缀名集合, client为Java中的MediaScannerClient对象。 */ MediaScanner *mp = (MediaScanner*)env->GetIntField(thiz, fields.context); constchar *pathStr = env->GetStringUTFChars(path, NULL); constchar *extensionsStr = env->GetStringUTFChars(extensions, NULL); ...... //构造一个Native层的MyMediaScannerClient,并使用Java那个Client对象做参数。 //这个Native层的Client简称为MyMSC。 MyMediaScannerClient myClient(env, client); //调用Native的MS扫描文件夹,并且把Native的MyMSC传进去。 mp->processDirectory(pathStr,extensionsStr, myClient, ExceptionCheck, env); ...... env->ReleaseStringUTFChars(path, pathStr); env->ReleaseStringUTFChars(extensions,extensionsStr); ...... } ~~~ processDirectory函数本身倒不难,但又冒出了几个我们之前没有接触过的类型,下面先来认识一下它们。 5. 到底有多少种对象? 图10-1展示了MediaScanner所涉及的相关类和它们之间的关系: :-: ![](http://img.blog.csdn.net/20150802165330508?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图10-1 MS相关类示意图 为了便于理解,便将Java和Native层的对象都画于图中。从上图可知: - Java MS对象通过mNativeContext指向Native的MS对象。 - Native的MyMSC对象通过mClient保存Java层的MyMSC对象。 - Native的MS对象调用processDirectory函数的时候会使用Native的MyMSC对象。 - 另外,图中Native MS类的processFile是一个虚函数,需要派生类来实现。 其中比较费解的是MyMSC对象。它们有什么用呢?这个问题真是一言难尽。下面通过processDirectory来探寻其中原因,这回得进入PVMediaScanner的领地了。