Android JNI
来源:互联网 发布:关于linux 的书籍 编辑:程序博客网 时间:2024/06/07 03:49
什么是JNI,Java Native Interface ,Java 本地调用。Java 虽然具有跨平台的特性,但是Java和具体的平台之间的隔离是通过JNI层来实现的,Android 中 Java 通过 JNI 层调用 Linux 中的接口来实现对应的功能。JNI 层一般是由 C C++ 文件编写。
Java 程序
1、加载对应的JNI库,同行的做法是放在类的 static 语句中加载
2、声明 native 函数,表示这个函数在 JNI 层实现
public class JNIDemo{ static { /* load */ System.loadLibrary("native");/* libnative.so */ } public native void hello(); public native int add(int a, int b); public native String str(String str); public native int [] array(int [] a); public static void main(String args[]){ JNIDemo d = new JNIDemo(); /* hello */ d.hello(); /* int */ System.out.println(d.add(1,2)); /* string */ System.out.println(d.str("hello world")); /* array */ int [] a = {1,2,3}; int [] b = d.array(a); for (int i = 0; i < b.length; i++) System.out.println(b[i]); }}
JNI C 程序
1、实现一个 JNI_OnLoad 函数,JNI_OnLoad 函数将在 java System.loadLibrary 后在该库中寻找并调用 JNI_OnLoad
2、一般在JNI_OnLoad 函数中注册一个 JNINativeMethod 类型的数组来表示 Java 与 JNI 中函数的映射关系(实际上只要在调用函数之前注册就行)
3、JNINativeMethod 中的数据类型可通过以下代码来获取,编译程序.class文件,在生成.h头文件
/* javac JNIDemo.java *//* javah -jni JNIDemo */
#include <stdio.h>#include <jni.h>#include <stdlib.h>/* java - c */#if 0typedef struct{char *name; //name in javachar *signature;//paramschar *fnPtr;//name in C}JNINativeMethod;#endifvoid c_hello(JNIEnv *env, jobject cls){printf("hello\n");}jint c_add(JNIEnv *env, jobject cls, jint a, jint b){return a + b;}jstring c_str(JNIEnv *env, jobject cls, jstring str){const jbyte *cstr;cstr = (*env)->GetStringUTFChars(env, str, NULL);if (cstr == NULL) {return NULL; /* OutOfMemoryError already thrown */}printf("Get string from java :%s\n", cstr);(*env)->ReleaseStringUTFChars(env, str, cstr);return (*env)->NewStringUTF(env, "return from c");}jintArray c_array(JNIEnv *env, jobject cls, jintArray arr){jint *carr;jint *oarr;jintArray rarr;jint i, n = 0;carr = (*env)->GetIntArrayElements(env, arr, NULL);if (carr == NULL) {return 0; /* exception occurred */}n = (*env)->GetArrayLength(env, arr);oarr = malloc(sizeof(jint) * n);if (oarr == NULL){(*env)->ReleaseIntArrayElements(env, arr, carr, 0);return 0;}for (i = 0; i < n; i++){oarr[i] = carr[n-1-i];}(*env)->ReleaseIntArrayElements(env, arr, carr, 0);/* create jintArray */rarr = (*env)->NewIntArray(env, n);if (rarr == NULL){return 0;}(*env)->SetIntArrayRegion(env, rarr, 0, n, oarr);free(oarr);return rarr;}static const JNINativeMethod methods[] = {{"hello", "()V", (void *)c_hello},{"add", "(II)I", (void *)c_add},{"str", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_str},{"array","([I)[I", (void *)c_array},};JNI_OnLoad(JavaVM *jvm, void *reserved){JNIEnv *env;jclass cls;if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)){return JNI_ERR;}//function of class in javacls = (*env)->FindClass(env, "JNIDemo");if (cls == NULL){return JNI_ERR;}(*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0]));return JNI_VERSION_1_4;}
MediaScanner 分析:
MediaScanner.java (frameworks\base\media\java\android\media)
public class MediaScanner{ static { System.loadLibrary("media_jni"); //libmedia_jni.so native_init(); } ... //声明本地方法 private native void processDirectory(String path, MediaScannerClient client); private native void processFile(String path, String mimeType, MediaScannerClient client); public native void setLocale(String locale); public native byte[] extractAlbumArt(FileDescriptor fd); private static native final void native_init(); private native final void native_setup(); private native final void native_finalize(); ...}
搜索一个 native 方法,processDirectory 来查找 JNI 层的代码位置:
android_media_MediaScanner.cpp (frameworks\base\media\jni)
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 },};这个文件中并没有 JNI_OnLoad 函数,但是实现了一个注册函数:
int register_android_media_MediaScanner(JNIEnv *env){ return AndroidRuntime::registerNativeMethods(env, kClassMediaScanner, gMethods, NELEM(gMethods));}android_media_MediaPlayer.cpp (frameworks\base\media\jni)
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */){ JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (register_android_media_ImageReader(env) < 0) { ALOGE("ERROR: ImageReader native registration failed"); goto bail; } if (register_android_media_MediaPlayer(env) < 0) { ALOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; } if (register_android_media_MediaRecorder(env) < 0) { ALOGE("ERROR: MediaRecorder native registration failed\n"); goto bail; } if (register_android_media_MediaScanner(env) < 0) { ALOGE("ERROR: MediaScanner native registration failed\n"); goto bail; } ....}
在另一个文件中的 JNI_OnLoad 函数中,统一注册了一些 JNINativeMethods .
在 JNI 文件中可以获得 Java 中的成员变量、成员方法
static voidandroid_media_MediaScanner_native_init(JNIEnv *env){ ALOGV("native_init"); jclass clazz = env->FindClass(kClassMediaScanner); if (clazz == NULL) { return; } // java: private long mNativeContext; fields.context = env->GetFieldID(clazz, "mNativeContext", "J");//获得成员变量 if (fields.context == NULL) { return; }}static voidandroid_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz){ ALOGV("native_setup"); MediaScanner *mp = new StagefrightMediaScanner; if (mp == NULL) { jniThrowException(env, kRunTimeException, "Out of memory"); return; } env->SetLongField(thiz, fields.context, (jlong)mp);//设置java中成员变量的值}
成员方法:
static voidandroid_media_MediaScanner_processDirectory( JNIEnv *env, jobject thiz, jstring path, jobject client){ ALOGV("processDirectory"); MediaScanner *mp = getNativeScanner_l(env, thiz); //unicode -> utf-8 const char *pathStr = env->GetStringUTFChars(path, NULL); MyMediaScannerClient myClient(env, client); ... env->ReleaseStringUTFChars(path, pathStr);}
class MyMediaScannerClient : public MediaScannerClient{public: MyMediaScannerClient(JNIEnv *env, jobject client) : mEnv(env), mClient(env->NewGlobalRef(client)), mScanFileMethodID(0), mHandleStringTagMethodID(0), mSetMimeTypeMethodID(0) { ALOGV("MyMediaScannerClient constructor"); jclass mediaScannerClientInterface = env->FindClass(kClassMediaScannerClient); if (mediaScannerClientInterface == NULL) { ALOGE("Class %s not found", kClassMediaScannerClient); } else { //获得 java 中的成员方法 mScanFileMethodID = env->GetMethodID( mediaScannerClientInterface, "scanFile", "(Ljava/lang/String;JJZZ)V"); mHandleStringTagMethodID = env->GetMethodID( mediaScannerClientInterface, "handleStringTag", "(Ljava/lang/String;Ljava/lang/String;)V"); mSetMimeTypeMethodID = env->GetMethodID( mediaScannerClientInterface, "setMimeType", "(Ljava/lang/String;)V"); } } .... virtual status_t scanFile(const char* path, long long lastModified, long long fileSize, bool isDirectory, bool noMedia) { mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize, isDirectory, noMedia); mEnv->DeleteLocalRef(pathStr); return checkAndClearExceptionFromCallback(mEnv, "scanFile"); }private: JNIEnv *mEnv; jobject mClient; jmethodID mScanFileMethodID; jmethodID mHandleStringTagMethodID; jmethodID mSetMimeTypeMethodID;};
mClient -> android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path,jobject client)
private native void processDirectory(String path, MediaScannerClient client);
public interface MediaScannerClient{ public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory, boolean noMedia); /** * Called by native code to return metadata extracted from media files. */ public void handleStringTag(String name, String value); /** * Called by native code to return mime type extracted from DRM content. */ public void setMimeType(String mimeType);}
阅读全文
1 0
- [JNI] Android JNI总结
- Android JNI
- Android JNI
- android JNI
- Android JNI
- android jni
- android JNI
- Android JNI
- android jni
- android JNI
- android JNI
- android JNI
- android jni
- Android JNI
- Android JNI
- Android JNI
- android JNI
- android jni
- html5+css媒体查询、多列+精灵雪碧图
- 215. Kth Largest Element in an Array
- 淘淘商城系列——添加商品同步到索引库以及消息机制测试
- SpringBoot学习笔记-集成其他组件框架记录
- linux exercise 24
- Android JNI
- 2_写一个点LED驱动
- JAVA操作Excel表格
- Git是怎样生成diff的:Myers算法
- 第一篇博文
- nodebb 安装指南
- GitHub详解(1)
- 解决clang"fatal error: 'stdio.h' file not found"问题
- Hdu2005 **