简单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文件。

时间: 2024-08-29 21:12:28

简单JNI使用demo的相关文章

mac实现jni的demo

今天在看ArrayList 源码时看到了System.arraycopy 这个方法,但是这个方法没有java实现. 后面一通查询查找,才知道 如下图 native是一个java调用c语言来实现的操作的jni.然后就写 了一个jni 的demo 1 编写带有 native java文件 public class HelloWorld { public native void hello(); static{ System.loadLibrary("hello"); } public st

Android JNI programming demo with Eclipse

用Eclipse 建立 JNI 的專案, 示範如何在 JAVA 調用 cpp 的函數. 我們將建立一個名稱為 jnidemo的專案, 在主Activity 將調用一個名為libHello.so 的 cpp 函數庫的 getVersion() 的函數, 將其返回字串寫在主Activity 的TextView 上. 首先用Eclipse建立一個新的 Android Activity 專案.  其他選項都用預設值就可以. 1. 稍微修改主活動配置 layout/activity_main.xml, 

设计模式-简单工厂(Demo)

简介 工厂都是创建型模式.用来NEW类的.本文章用一个故事讲述了简单工厂模式 故事 在遥远的未来.chenchen我生活条件不错.但是每天都要做饭.chenchen很懒.只想吃.不想干.所以就请了个女仆给chenchen做饭吃.女仆很牛.chenchen只要说.我要吃牛排.不一会.牛排就做好了放在桌子上.我又说还要红酒.女仆开好红酒.倒好放在桌子上.美滋滋的哈!小肉吃着.小酒喝着.美女陪着此等逍遥快活! 是什么? 代替客户端NEW类.客户端与多个类解耦 为什么要用? 上述故事.因为我做很多饭.要

Xamarin.Android再体验之简单的登录Demo

一.前言 在空闲之余,学学新东西 二.服务端的代码编写与部署 这里采取的方式是MVC+EF返回Json数据,(本来是想用Nancy来实现的,想想电脑太卡就不开多个虚拟机了,用用IIS部署也好) 主要是接受客户端的登陆请求,服务器端返回请求的结果 这里的内容比较简单不在啰嗦,直接上代码了: 1 using System.Linq; 2 using System.Web.Mvc; 3 namespace Catcher.AndroidDemo.EasyLogOn.Service.Controller

php 简单实现webSocket(demo)

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据. 在 WebSocket API 中,浏览器和服务器只需要完成一次握手的动作,浏览器和服务器之间就形成了一条快速通道创建持久性的连接,两者之间就直接可以数据互相传送.(长连接,循环连接的不算) 现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询.轮询是在特定的的时间间隔(如每1秒),由浏览器对

vue+node+es6+webpack创建简单vue的demo

闲聊: 小颖之前一直说是写一篇用vue做的简单demo的文章,然而小颖总是给自己找借口,说没时间,这一没时间一下就推到现在了,今天抽时间把这个简单的demo整理下,给大家分享出来,希望对大家也有所帮助. 前期准备: 1.安装node 安装包地址这个里面有两个安装包大家可以根据自己的需求选择安装4.4.4版本或者6.2.0版本,小颖选择的是6.2.0. 2.Atom编辑器,这个大家可以根据自己的喜好选择自己喜欢的编辑器,所以小颖就不发下载链接了,大家有需求的话可以百度下嘻嘻. 目录: 创建项目:

C#开发微信公众平台-就这么简单(附Demo)

写在前面 阅读目录: 服务号和订阅号 URL配置 创建菜单 查询.删除菜单 接受消息 发送消息(图文.菜单事件响应) 示例Demo下载 后记 最近公司在做微信开发,其实就是接口开发,网上找了很多资料,当然园友也写了很多教程,但都是理论说了一大堆,实用指导或代码很少.如果你自己仔细研究下,其实就那么点东西,C#实现起来也很简单,原本不想写这篇文章的,但是本人当时摸索走了很多弯路,这边总结下,希望初次接触微信公众平台的朋友别像当时的我一样. 自己动手,丰衣足食. 服务号和订阅号 服务号是公司申请的微

Comet入门及最简单的Java Demo

在浏览网页的时候,假设有新的消息,怎样接收到?HTTP协议不能由server主动给client发送消息. 1.刷微博.逛论坛贴吧,想看最新的信息怎么办?F5刷新一下就OK了! 2.上面一种方式是被动的,假设用户不去刷新页面,就看不到消息.怎样让server主动推送消息给client浏览器,一种方式是用setInterval来Ajax定时刷新. 这样一来.刷新操作不是由用户来操作.而是由浏览器去自己主动发起请求.用户无法察觉到,给用户的感觉就是server主动推送消息给用户. 实际上这样的方式非常

zookeeper 简单的代码demo

写了一个关于zookeepeer应用的简单demo 服务端定时的向zookeeper集群注册,客户端监听zookeeper服务节点变化,一旦变化,立刻响应,更新服务端列表 服务端代码: #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h> #include <iostream> using namespace std; void InitWatch(zhandle_t* zh, int