JNI使用详解(一)

       Android应用开发很少直接使用JNI技术,但是JNI技术却在广泛使用在Android系统中,只是被google很好的封装起来了,JNI是Java Native Interface的缩写,也就是我们常说的Java本地调用。我们可以用JNI技术实现java中去调用Native语言(C/C++),也可以在Native中去调用java语言;

       Java也是能实现Native语言所实现的功能,但是既然Native已经实现,我们又何必去重复制造轮子呢。JNI是一个架在Java与Native两个岛屿之间的桥梁。

                                JNI使用详解(一)_第1张图片

   我们以MediaScanner类来研究下Android中如何使用JNI技术的,在Java中我们MediaScanner在framework\base\media\java\android\media目录,这个类中的某些方法会去调用Native中的方法。在JNI层,对应的是libmedia_jni.so文件,media_jni是JNI库的名字,media是Native层库的名字,也就是libmedia库。jni表示他是一个jni库,命名规则基本上采用 “lib模块名_jni.so”的命名方式。Native层对应的是libmedia.so,具体的功能实现也是在这里。Java代码通过JNI库libmedia_jni.so和Native层libmedia.so交互。注意Java虚拟机只能识别加载动态库。

      我们来看MediaScanner.java文件,主要加载JNI库,还有一个是调用native函数。基本上在任何地方都可以加载这个库,只要在调用native函数前,通行的做法是在类的static语句中加载,调用System.loadLibray方法就可以,该方法的参数是动态库的名字。

 
  
public class MediaScanner
{
    static {  
        System.loadLibrary("media_jni");//加载对应的JNI库,media_jni是JNI库名,在加载的时候会扩展成libmedia_jni.so
        native_init();//调用native_init函数
    }
....
public void scanDirectories(String[] directories,String volumeName) {
....
}
....
private static native final void native_init(); //声明一个native函数。native为Java的关键字,表示会由Native层实现
....
private native void processFile(String path,String mimeType, MediaScannerClient client);
....
}

   MediaScanner的JNI层代码在android_media_MediaScanner.cpp中,代码路径framewor/base/media/jni

 

这个函数是native_init的JNI层实现
static void android_media_MediaScanner_native_init(JNIEnv *env)
{
    ALOGV("native_init");
    jclass clazz = env->FindClass(kClassMediaScanner);
    if (clazz == NULL) {
        return;
    }

    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
    if (fields.context == NULL) {
        return;
    }
}
这是processFile在JNI中的实现

static void
android_media_MediaScanner_processFile(
        JNIEnv *env, jobject thiz, jstring path,
        jstring mimeType, jobject client)
{
    ALOGV("processFile");

    // Lock already hold by processDirectory
    MediaScanner *mp = getNativeScanner_l(env, thiz);
    if (mp == NULL) {
        jniThrowException(env, kRunTimeException, "No scanner available");
        return;
    }

    if (path == NULL) {
        jniThrowException(env, kIllegalArgumentException, NULL);
        return;
    }

    const char *pathStr = env->GetStringUTFChars(path, NULL);
    if (pathStr == NULL) {  // Out of memory
        return;
    }

    const char *mimeTypeStr =
        (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
    if (mimeType && mimeTypeStr == NULL) {  // Out of memory
        // ReleaseStringUTFChars can be called with an exception pending.
        env->ReleaseStringUTFChars(path, pathStr);
        return;
    }

    MyMediaScannerClient myClient(env, client);
    MediaScanResult result = mp->processFile(pathStr, mimeTypeStr, myClient);
    if (result == MEDIA_SCAN_RESULT_ERROR) {
        ALOGE("An error occurred while scanning file '%s'.", pathStr);
    }
    env->ReleaseStringUTFChars(path, pathStr);
    if (mimeType) {
        env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
    }
}
    java层是通过文件名找到JNI层的android_media_MediaScanner_native_init,到这里Java层的native函数与JNI层对应的实现函数关联起来了。

你可能感兴趣的:(Android系统)