Android系统开发(二)JNI

前言

    在嵌入式底层工程师的世界里JNI就是java跟c/c++世界沟通的桥梁,包括我也是这样认为了很多年;前几天跟做app的同事聊天,无意中发现在他们的知识体系中jni是Java世界和Native世界的媒介。"Native"没错这个才是理解的关键。在java语言出现之前,就有很多程序和库都是由Native语言写的,利用现有的库开发事半功倍同时可以保证更好的性能。 就是好比Android的底层是linux内核——c语言世界的极致表达。 今天整理一下JNI。

一、通过一个案例开始说起吧java让c说声"Hello world!"

1、java

public class JavaSayHello{
	/*通过构造块来加载C库*/
	static{
		System.loadLibrary("native");
	}
	public native String java_say_to_c(String str); //声明为native方法
	
	public static void main (String args[]){
		JavaSayHello oTmp = new JavaSayHello(); //执行此句话时会调用构造块
        /*调用c中的映射的函数打印Hello world!*/
	System.out.println(oTmp.java_say_to_c("Hello world!"))
    }
}

2、c (c程序里的工作量比较多,包括建立映射表、JNI加载C库、被调用的c程序)

1)映射表结构

static const JNINativeMethod methods[] = {
	{"java_say_to_c", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_get_from_java},
};

2)c程序

jstring JNICALL c_get_from_java(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, "This is c env return...\n");
}

3)系统加载c函数

/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
	JNIEnv *env;
	jclass cls;

	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "JavaSayHello");
	if (cls == NULL) {
		return JNI_ERR;
	}

	/* 2. map (java) java_say_to_c<-->(c) c_get_from_java*/
	if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) //这个数字1代表映射了一个方法映射数组的个数
		return JNI_ERR;

	return JNI_VERSION_1_4;
}

基本逻辑可以理解为:

1、java在实例化对象oTmp时构造块会加载C库(System.loadLibrary("native");)

2、JNI_OnLoad会先获取java环境,通过环境找到java中的类(这部分自己理解),然后通过methods建立的数组映射表,建立一一映射关系。

3、在java中调用 方法,方法通过映射找到函数,然后调用对应的c函数。

二、实际编译运行测试:

1、

编译c文件 native.c: gcc -I /home/bupt/miao/box/soft/java-7-openjdk-amd64/include/ -fPIC -shared -o libnative.so native.c

-I /home/bupt/miao/box/soft/java-7-openjdk-amd64/include/ 是指定编译的中jni.h的路径,根据自己的JDK安装路径选择。

2、

编译java:javac JavaSayHello.java
注:编译错误

Exception in thread "main" java.lang.UnsatisfiedLinkError: no native in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1889)
	at java.lang.Runtime.loadLibrary0(Runtime.java:849)
	at java.lang.System.loadLibrary(System.java:1088)
	at JavaSayHello.(JavaSayHello.java:4)
 解决方法:
export LD_LIBRARY_PATH=.
运行结果:
bupt@machine:~/miao/project/android/jni/myJNI$ java JavaSayHello 
Get string from java :Hello world!
This is c env return ...

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