简单JNI使用demo

android中使用JNI的小例子,直接上代码。

首先是Java类JniClient,定义native方法,User实体类就不上代码了,就简单定义了三个属性,name、age、sex。

 1 package com.example.ndkdemo;
 2 
 3 public class JniClient {
 4     
 5     /**
 6      * 通过JNI简单输出字符串
 7      * @return
 8      */
 9     static public native String printStr();
10     
11     /**
12      * 通过JNI简单进行整形加法操作
13      * @param a
14      * @param b
15      * @return
16      */
17     static public native int addInt(int a, int b);
18     
19     /**
20      * 通过JNI输入JAVA对象信息
21      * @param user
22      * @return
23      */
24     static public native String printUser(User user);
25     
26     /**
27      * 通过JNI创建java对象
28      * @param name
29      * @param age
30      * @param sex
31      * @return
32      */
33     static public native User newUser(String name, int age, String sex);
34     
35     /**
36      * 通过JNI调用无参构造函数创建java对象并且设置相应属性值
37      * @param name
38      * @param age
39      * @param sex
40      * @return
41      */
42     static public native User newUserNoArgs(String name, int age, String sex);
43 }

 

然后使用cmd进入工程的classes目录通过javah命令生成c代码的头文件,命令:javah com.example.ndkdemo.JniClient ,这里生成的文件名字为:com_example_ndkdemo_JniClient.h

在工程下面新建一个jni目录,将生成的头文件拷贝到jni目录下面,创建com_example_ndkdemo_JniClient.c文件,在com_example_ndkdemo_JniClient.c文件里面实现各个native方法,代码如下:

  1 #include "com_example_ndkdemo_JniClient.h"
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 
  5 // 引入log头文件
  6 #include <android/log.h>
  7 // log标签
  8 #define TAG "jniCLient"
  9 // 定义info信息
 10 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
 11 // 定义debug信息
 12 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
 13 // 定义error信息
 14 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
 15 
 16 
 17 #ifdef __cplusplus
 18 extern "C"
 19 {
 20 #endif
 21 /*
 22  * Class:     com_example_ndkdemo_JniClient
 23  * Method:    printStr
 24  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 25  */
 26 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printStr
 27   (JNIEnv *env, jclass arg)
 28 {
 29     jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");
 30     LOGI("log from jni");
 31     return str;
 32 }
 33 
 34 /*
 35 * Class:     com_example_ndkdemo_JniClient
 36 * Method:    AddInt
 37 * Signature: (II)I
 38 */
 39 JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniClient_addInt
 40   (JNIEnv *env, jclass arg, jint a, jint b)
 41 {
 42     return a + b;
 43 }
 44 
 45 /**
 46  * printUser
 47  * jclass arg:因为方法为static,所以需要传入jclass参数,表明是哪个类的方法
 48  */
 49 /**
 50  *1)如果是C++代码,则用(*env),如果是C代码,则用env,否则报错: request for member 'GetObjectClass' in something not a structure or union
 51  *2)所有方法都加了一个参数env,否则报错:too few arguments to function '(*env)->GetObjectClass'
 52  *3)不能把.C文件改成.CPP文件,否则没有规则可以创建“out/apps/JNI_0529/armeabi/objs/JNI_0529/android_jni_MyJNINative.o”需要的目标“apps/JNI_0529/proje*ct/jni/android_jni_MyJNINative.c”
 53  * 一个小例子错误真多啊!!NDK不简单啊!!
 54  */
 55 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printUser
 56   (JNIEnv *env, jclass arg, jobject obj)
 57 {
 58     LOGI("add from jni--打印用户信息--");
 59     //获得obj对象的类
 60     jclass cls_objClass = (*env)->GetObjectClass(env, obj);
 61     /**
 62      * 获得obj对象中特定方法getName的id
 63      * env
 64      * cls_objClass         方法所属类
 65      * getName              方法名字
 66      * ()Ljava/lang/String; 方法签名
 67      */
 68     jmethodID nameMethodId = (*env)->GetMethodID(env, cls_objClass, "getName", "()Ljava/lang/String;");
 69     /**
 70      * 调用obj对象的特定方法getName
 71      * obj      调用方法的目标对象
 72      * nameMethodId   调用方法的方法名
 73      * ...    后面还可以添加方法需要的参数
 74      */
 75     jstring js_name = (jstring)(*env)->CallObjectMethod(env, obj, nameMethodId);
 76     //将jstring转为c中的字符数组
 77     const char * name = (char *)(*env)->GetStringUTFChars(env, js_name, 0);
 78 
 79     jmethodID ageMethodId = (*env)->GetMethodID(env, cls_objClass, "getAge", "()I");
 80     jint ji_age = (*env)->CallIntMethod(env, obj, ageMethodId);
 81 
 82     jmethodID sexMethodId = (*env)->GetMethodID(env, cls_objClass, "getSex", "()Ljava/lang/String;");
 83     jstring js_sex = (jstring)(*env)->CallObjectMethod(env, obj, sexMethodId);
 84     const char * sex = (char *)(*env)->GetStringUTFChars(env, js_sex, 0);
 85 
 86     //打印信息
 87     LOGI("user info----name:%s, age:%d, sex:%s.", name, ji_age, sex);
 88 
 89     //释放资源
 90     (*env)->ReleaseStringUTFChars(env, js_name, name);
 91     (*env)->ReleaseStringUTFChars(env, js_sex, sex);
 92 //    printf("%s", str);
 93     return js_name;
 94 }
 95 
 96 /**
 97  * 创建一个对象(调用有参构造函数)
 98  */
 99 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUser
100   (JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
101 {
102     //创建一个class的引用,使用类的全包名
103     jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
104     //注意这里方法的名称是"<init>",它表示这是一个构造函数
105     jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
106     //获得一实例,后面接构造函数参数
107 //    jobject obj = (*env)->NewObject(env, cls, id, name, age, sex);
108     jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
109     jstring jsex = (*env)->NewStringUTF(env, "jni-男");
110     jobject obj = (*env)->NewObject(env, cls, id, jname, 18L, jsex);
111 
112     return obj;
113 }
114 
115 /**
116  * 创建一个对象(调用无参构造函数)
117  */
118 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUserNoArgs
119   (JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
120 {
121     //创建一个class的引用,使用类的全包名
122     jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
123     //注意这里方法的名称是"<init>",它表示这是一个构造函数
124     jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "()V");
125     //获得一实例,后面接构造函数参数
126     jobject obj = (*env)->NewObject(env, cls, id);
127     jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
128     jstring jsex = (*env)->NewStringUTF(env, "jni-男");
129 
130     //获取jfieldID
131     jfieldID nameId = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
132     jfieldID ageId = (*env)->GetFieldID(env, cls, "age", "I");
133     jfieldID sexId = (*env)->GetFieldID(env, cls, "sex", "Ljava/lang/String;");
134     (*env)->SetObjectField(env, obj, nameId, jname);
135     (*env)->SetIntField(env, obj, ageId, 18L);
136     (*env)->SetObjectField(env, obj, sexId, jsex);
137 
138     return obj;
139 }
140 
141 #ifdef __cplusplus
142 }
143 #endif

 

代码注释写的很详细,就不多讲了。

下面创建在jni目录下面创建编译文件Android.mk,内容如下:

1 LOCAL_PATH := $(call my-dir)
2 include $(CLEAR_VARS)
3 LOCAL_MODULE := NDKDemo
4 LOCAL_SRC_FILES := com_example_ndkdemo_JniClient.c
5 LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
6 include $(BUILD_SHARED_LIBRARY)

编译过程可以参考网上的,网上很多。下面是在android中调用的代码:

 1 package com.example.ndkdemo;
 2 
 3 import android.os.Bundle;
 4 import android.support.v7.app.ActionBarActivity;
 5 import android.util.Log;
 6 import android.view.View;
 7 import android.view.View.OnClickListener;
 8 import android.widget.Button;
 9 import android.widget.EditText;
10 import android.widget.Toast;
11 
12 public class MainActivity extends ActionBarActivity {
13 
14     static {
15         System.loadLibrary("NDKDemo");
16     }
17     
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.activity_main);
22         findViewById(R.id.button).setOnClickListener(new OnClickListener() {
23             @Override
24             public void onClick(View v) {
25                 //调用jni返回字符串
26                 //Toast.makeText(MainActivity.this, JniClient.printStr(), Toast.LENGTH_LONG).show();
27                 User user = new User("刘玲", 25, "男hahaah");
28                 String name = JniClient.printUser(user);
29                 Log.e("name", name + "");
30 //                User user = JniClient.newUser("liuling", 18, "男");
31 //                User user = JniClient.newUserNoArgs("liuling", 18, "男");
32 //                Toast.makeText(MainActivity.this, user.toString(), Toast.LENGTH_LONG).show();
33             }
34         });
35         final EditText num1 = (EditText) findViewById(R.id.num1);
36         final EditText num2 = (EditText) findViewById(R.id.num2);
37         final EditText result = (EditText) findViewById(R.id.result);
38         Button addBtn = (Button) findViewById(R.id.addBtn);
39         
40         addBtn.setOnClickListener(new OnClickListener() {
41             @Override
42             public void onClick(View v) {
43                 int n1 = Integer.valueOf(num1.getText().toString().trim());
44                 int n2 = Integer.valueOf(num2.getText().toString().trim());
45                 int n3 = JniClient.addInt(n1, n2);
46                 result.setText(n3 + "");
47             }
48         });
49         
50     }
51 
52     
53 }

这里要注意14-16行,一定要加载so文件。

 

posted @ 2015-08-07 18:26  残剑_  阅读(1954)  评论(0编辑  收藏  举报