主机环境: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)
这个格式是一个固定的mk文件编写格式,第一句话是指明当前目录即mk所在目录;第二句话是清除LOCAL_XXX变量,不然会对我们编译产生影响;第三句话是指明所要生成的库的名字;第四句话是指明需要的C文件,最后一句话是指明生成共享库,在该目录下执行¥NDK/ndk-build,会在libs目录下生成所需要的libhello-jni.so库文件
打开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控件显示被调函数返回的字符串内容,效果如下:
小弟才疏学浅,如果错误请大家指正,以便小弟得到提升。写这个文章失败了两次,所以以后大家写文章千万记得随时保存,小蝶就是血淋淋的教训那!!!