主机环境:UBUNTU10.10
编译器:android-ndk-r8b
由于在编写android程序时需要用到C语言编写的库函数,因此涉及到了JNI知识,在此记录下一些心得,学习JNI利用NDK提供的最简单的例子来做下示范,在NDK目录下有一个samples目录,其中放有一些jni的示例,这里我们用最简单的例子hello-jni
将hello-jni目录拷贝到/key_C/android目录下,这个是我的jni程序目录,大家可以自行设置,进入该目录下的jni目录,可以看到两个文件Android.mk和hello-jni.c,其中Android.mk文件相当于linux下的Makefile文件,hello-jni.c是我们需要用到的库函数实现体,打开该文件
#include <string.h> #include <jni.h> /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); }
可以看到文件很简单,因为是jni编程所以先要包含jni.h头文件,(欲哭无泪,写了好久才写好,居然保存失败,在一刷新就只剩下这么点了,又要重新写,唉~~~)
文件中也指明了java代码所在的路径,我们可以看到该函数的名字有点长,我们先分析哈,首先是返回类型jstring,涉及到jni编程
Java类型 本地类型 描述 boolean jboolean C/C++8位整型 byte jbyte C/C++带符号的8位整型 char jchar C/C++无符号的16位整型 short jshort C/C++带符号的16位整型 int jint C/C++带符号的32位整型 long jlong C/C++带符号的64位整型e float jfloat C/C++32位浮点型 double jdouble C/C++64位浮点型 Object jobject 任何Java对象,或者没有对应java类型的对象 Class jclass Class对象 String jstring 字符串对象 Object[] jobjectArray 任何对象的数组 boolean[] jbooleanArray 布尔型数组 byte[] jbyteArray 比特型数组 char[] jcharArray 字符型数组 short[] jshortArray 短整型数组 int[] jintArray 整型数组 long[] jlongArray 长整型数组 float[] jfloatArray 浮点型数组 double[] jdoubleArray 双浮点型数组上面是一些数据类型的对应表,
接着是Java,这个是固定的,后面是android工程的包名以下划线隔开而不是以点分割,接着是类名,指明该函数是由那个类来调用,最后是函数名stringFromJNI以及参数JNIEnv* env,jobject thiz,前者是一个指向函数列表的指针,后面相当于this指针,这两个参数是固定的,如果读者有自己想要传递的参数加在后面即可。
函数实现体中只有一句代码将“hello from JNI!”通过env传递给主调函数。
下面说下Android.mk文件
Android.mk文件相当于linux下的Makefile文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY)
打开java文件
package com.example.hellojni; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class HelloJni extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText( stringFromJNI() ); //调用函数 setContentView(tv); } /* A native method that is implemented by the * 'hello-jni' native library, which is packaged * with this application. */ public native String stringFromJNI(); //声明函数 /* This is another native method declaration that is *not* * implemented by 'hello-jni'. This is simply to show that * you can declare as many native methods in your Java code * as you want, their implementation is searched in the * currently loaded native libraries only the first time * you call them. * * Trying to call this function will result in a * java.lang.UnsatisfiedLinkError exception ! */ public native String unimplementedStringFromJNI(); //声明函数 /* this is used to load the 'hello-jni' library on application * startup. The library has already been unpacked into * /data/data/com.example.hellojni/lib/libhello-jni.so at * installation time by the package manager. */ static { System.loadLibrary("hello-jni"); //加载库文件 } }在java文件中调用C语言函数,首先需要加载库文件,然后用native关键字声明该函数,只需写函数名字即可,env和thiz参数省略,只需写自己所需要的参数即可,这里为空。之后就可以在程序中调用该函数了,这里是用TextView控件显示被调函数返回的字符串内容,效果如下:
小弟才疏学浅,如果错误请大家指正,以便小弟得到提升。写这个文章失败了两次,所以以后大家写文章千万记得随时保存,小蝶就是血淋淋的教训那!!!