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的例子。