Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97955
  • 博文数量: 21
  • 博客积分: 451
  • 博客等级: 一等列兵
  • 技术积分: 215
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-03 20:46
个人简介

记录技术旅程

文章分类

全部博文(21)

文章存档

2014年(3)

2011年(18)

我的朋友

分类: Java

2011-05-13 10:37:33

1、通过Eclipse创建一个android项目SimpleJniPrj,package="com.example.android.simplejni"。
SimpleJNI.java:
  1. package com.example.android.simplejni;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;

  5. public class SimpleJNI extends Activity {
  6.     
  7.     /** Called when the activity is first created. */
  8.     @Override
  9.     public void onCreate(Bundle savedInstanceState) {
  10.         super.onCreate(savedInstanceState);
  11.         TextView tv = new TextView(this);
  12.         Native t = new Native();
  13.         t.nativeInit();
  14.         int sum = t.nativeAdd(2, 3);
  15.         tv.setText("2 + 3 = " + Integer.toString(sum));
  16.         tv.append("\n i = " + Integer.toString(t.getCallbackResult()));
  17.         setContentView(tv);
  18.     }
  19. }

  20. class Native{
  21.     private int i=0;
  22.     
  23.     static {
  24.         // The runtime will add "lib" on the front and ".o" on the end of
  25.         // the name supplied to loadLibrary.
  26.         System.loadLibrary("simplejni");
  27.     }
  28.     
  29.     native void nativeInit();
  30.     
  31.     native int nativeAdd(int a, int b);
  32.     
  33.     public void callback(){
  34.         i++;
  35.         System.out.printf("java callback i=%d\n", i);
  36.     }
  37.     
  38.     public int getCallbackResult(){
  39.         return i;
  40.     }
  41. }
在上面的java文件中,实现了一个SimpleJNI Activity类和一个Native类。Native类实现了native库的加载、native方法的声明和callback方法(被C++调用)的实现。Simple类通过实例Native对象,调用Native类中的native方法。

2、在C++中实现native方法。实现native方法需要通过javah产生native方法的头文件,但是,这样生成的C++的native方法名称可读性差,不方便使用。利用通过System.loadLibrary加载native库时JNI_OnLoad将被调用的特性,通过实现JNI_OnLoad方法将自定义C++中的native方法注册到虚拟机中。从而实现对自主定义native方法名。
下面是关于native.cpp的描述:
  1. static JNINativeMethod methods[] = {
  2.   {"nativeInit", "()V", (void*)init},
  3.   {"nativeAdd", "(II)I", (void*)add},
  4. };

typedef struct {

const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;

JNINativeMethod是Java 和 C 函数的映射表结构体。第一个变量name是Java中函数的名字;第二个变量signature,用字符串是描述了函数的参数和返回值;第三个变量fnPtr是函数指针,指向C函数。其中,init和add为本地的方法,分别对应java中的nativeInit和nativeAdd方法。

  1. static jint
  2. add(JNIEnv *env, jobject thiz, jint a, jint b) {
  3. int result = a + b;
  4.     LOGI("%d + %d = %d", a, b, result);

  5.     jclass cls = env->GetObjectClass(thiz);
  6.     LOGI("cls=0x%x", cls);

  7.     jmethodID method_id = env->GetMethodID(cls, "callback", "()V");
  8.     LOGI("method_id=0x%x",method_id);

  9.     env->CallVoidMethod(thiz, method_id);

  10.     return result;
  11. }

  12. static void
  13. init(JNIEnv *env, jobject thiz){
  14.     gObject = env->NewWeakGlobalRef(thiz);
  15.     LOGI("gObject=0x%x",gObject);
  16. }

方法add实现了将两个参数a和b相加并返回结果,同时调用了java域的callback方法,而参数env表示java运行的环境,thiz表示在java域中调用此方法的对象实例。java通过调用init方法初始化native运行环境,比如在此存储一个全局的对象。

3、通过JNI_OnLoad方法注册自定义的native方法到虚拟机中。
  1. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  2. {
  3.     UnionJNIEnvToVoid uenv;
  4.     uenv.venv = NULL;
  5.     jint result = -1;
  6.     JNIEnv* env = NULL;
  7.     
  8.     LOGI("JNI_OnLoad");
  9.     
  10.     setJavaVM(vm);

  11.     if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
  12.         LOGE("ERROR: GetEnv failed");
  13.         goto bail;
  14.     }
  15.     env = uenv.env;

  16.     if (registerNatives(env) != JNI_TRUE) {
  17.         LOGE("ERROR: registerNatives failed");
  18.         goto bail;
  19.     }
  20.     result = JNI_VERSION_1_4;
  21.     
  22. bail:
  23.     return result;
  24. }

static const char *classPathName = "com/example/android/simplejni/Native";

static int registerNatives(JNIEnv* env)
{
  if (!registerNativeMethods(env, classPathName,
                 methods, sizeof(methods) / sizeof(methods[0]))) {
    return JNI_FALSE;
  }

  return JNI_TRUE;
}


/*
 * Register several native methods for one class.
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;

    clazz = env->FindClass(className);
    if (clazz == NULL) {
        LOGE("Native registration unable to find class '%s'", className);
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        LOGE("RegisterNatives failed for '%s'", className);
        return JNI_FALSE;
    }

    return JNI_TRUE;
}
4、使用NDK编译native.cpp生成的libsimplejni.so,并将其拷贝到java项目中的SimpleJNI\libs\armeabi中。最后编译java项目,并运行。


阅读(2936) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~