简单JNI使用demo
android中使用JNI的小例子,直接上代码。
首先是Java类JniClient,定义native方法,User实体类就不上代码了,就简单定义了三个属性,name、age、sex。
package com.example.ndkdemo;
public class JniClient {
/**
* 通过JNI简单输出字符串
* @return
*/
static public native String printStr();
/**
* 通过JNI简单进行整形加法操作
* @param a
* @param b
* @return
*/
static public native int addInt(int a, int b);
/**
* 通过JNI输入JAVA对象信息
* @param user
* @return
*/
static public native String printUser(User user);
/**
* 通过JNI创建java对象
* @param name
* @param age
* @param sex
* @return
*/
static public native User newUser(String name, int age, String sex);
/**
* 通过JNI调用无参构造函数创建java对象并且设置相应属性值
* @param name
* @param age
* @param sex
* @return
*/
static public native User newUserNoArgs(String name, int age, String sex);
}
然后使用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方法,代码如下:
#include "com_example_ndkdemo_JniClient.h"
#include <stdlib.h>
#include <stdio.h> // 引入log头文件
#include <android/log.h>
// log标签
#define TAG "jniCLient"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__) #ifdef __cplusplus
extern "C"
{
#endif
/*
* Class: com_example_ndkdemo_JniClient
* Method: printStr
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printStr
(JNIEnv *env, jclass arg)
{
jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");
LOGI("log from jni");
return str;
} /*
* Class: com_example_ndkdemo_JniClient
* Method: AddInt
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniClient_addInt
(JNIEnv *env, jclass arg, jint a, jint b)
{
return a + b;
} /**
* printUser
* jclass arg:因为方法为static,所以需要传入jclass参数,表明是哪个类的方法
*/
/**
*1)如果是C++代码,则用(*env),如果是C代码,则用env,否则报错: request for member 'GetObjectClass' in something not a structure or union
*2)所有方法都加了一个参数env,否则报错:too few arguments to function '(*env)->GetObjectClass'
*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”
* 一个小例子错误真多啊!!NDK不简单啊!!
*/
JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printUser
(JNIEnv *env, jclass arg, jobject obj)
{
LOGI("add from jni--打印用户信息--");
//获得obj对象的类
jclass cls_objClass = (*env)->GetObjectClass(env, obj);
/**
* 获得obj对象中特定方法getName的id
* env
* cls_objClass 方法所属类
* getName 方法名字
* ()Ljava/lang/String; 方法签名
*/
jmethodID nameMethodId = (*env)->GetMethodID(env, cls_objClass, "getName", "()Ljava/lang/String;");
/**
* 调用obj对象的特定方法getName
* obj 调用方法的目标对象
* nameMethodId 调用方法的方法名
* ... 后面还可以添加方法需要的参数
*/
jstring js_name = (jstring)(*env)->CallObjectMethod(env, obj, nameMethodId);
//将jstring转为c中的字符数组
const char * name = (char *)(*env)->GetStringUTFChars(env, js_name, ); jmethodID ageMethodId = (*env)->GetMethodID(env, cls_objClass, "getAge", "()I");
jint ji_age = (*env)->CallIntMethod(env, obj, ageMethodId); jmethodID sexMethodId = (*env)->GetMethodID(env, cls_objClass, "getSex", "()Ljava/lang/String;");
jstring js_sex = (jstring)(*env)->CallObjectMethod(env, obj, sexMethodId);
const char * sex = (char *)(*env)->GetStringUTFChars(env, js_sex, ); //打印信息
LOGI("user info----name:%s, age:%d, sex:%s.", name, ji_age, sex); //释放资源
(*env)->ReleaseStringUTFChars(env, js_name, name);
(*env)->ReleaseStringUTFChars(env, js_sex, sex);
// printf("%s", str);
return js_name;
} /**
* 创建一个对象(调用有参构造函数)
*/
JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUser
(JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
{
//创建一个class的引用,使用类的全包名
jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
//注意这里方法的名称是"<init>",它表示这是一个构造函数
jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
//获得一实例,后面接构造函数参数
// jobject obj = (*env)->NewObject(env, cls, id, name, age, sex);
jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
jstring jsex = (*env)->NewStringUTF(env, "jni-男");
jobject obj = (*env)->NewObject(env, cls, id, jname, 18L, jsex); return obj;
} /**
* 创建一个对象(调用无参构造函数)
*/
JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUserNoArgs
(JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
{
//创建一个class的引用,使用类的全包名
jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
//注意这里方法的名称是"<init>",它表示这是一个构造函数
jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "()V");
//获得一实例,后面接构造函数参数
jobject obj = (*env)->NewObject(env, cls, id);
jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
jstring jsex = (*env)->NewStringUTF(env, "jni-男"); //获取jfieldID
jfieldID nameId = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
jfieldID ageId = (*env)->GetFieldID(env, cls, "age", "I");
jfieldID sexId = (*env)->GetFieldID(env, cls, "sex", "Ljava/lang/String;");
(*env)->SetObjectField(env, obj, nameId, jname);
(*env)->SetIntField(env, obj, ageId, 18L);
(*env)->SetObjectField(env, obj, sexId, jsex); return obj;
} #ifdef __cplusplus
}
#endif
代码注释写的很详细,就不多讲了。
下面创建在jni目录下面创建编译文件Android.mk,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := NDKDemo
LOCAL_SRC_FILES := com_example_ndkdemo_JniClient.c
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
编译过程可以参考网上的,网上很多。下面是在android中调用的代码:
package com.example.ndkdemo; import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast; public class MainActivity extends ActionBarActivity { static {
System.loadLibrary("NDKDemo");
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//调用jni返回字符串
//Toast.makeText(MainActivity.this, JniClient.printStr(), Toast.LENGTH_LONG).show();
User user = new User("刘玲", 25, "男hahaah");
String name = JniClient.printUser(user);
Log.e("name", name + "");
// User user = JniClient.newUser("liuling", 18, "男");
// User user = JniClient.newUserNoArgs("liuling", 18, "男");
// Toast.makeText(MainActivity.this, user.toString(), Toast.LENGTH_LONG).show();
}
});
final EditText num1 = (EditText) findViewById(R.id.num1);
final EditText num2 = (EditText) findViewById(R.id.num2);
final EditText result = (EditText) findViewById(R.id.result);
Button addBtn = (Button) findViewById(R.id.addBtn); addBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int n1 = Integer.valueOf(num1.getText().toString().trim());
int n2 = Integer.valueOf(num2.getText().toString().trim());
int n3 = JniClient.addInt(n1, n2);
result.setText(n3 + "");
}
}); } }
这里要注意14-16行,一定要加载so文件。
简单JNI使用demo的更多相关文章
- Xamarin.Android再体验之简单的登录Demo
一.前言 在空闲之余,学学新东西 二.服务端的代码编写与部署 这里采取的方式是MVC+EF返回Json数据,(本来是想用Nancy来实现的,想想电脑太卡就不开多个虚拟机了,用用IIS部署也好) 主要是 ...
- mac实现jni的demo
今天在看ArrayList 源码时看到了System.arraycopy 这个方法,但是这个方法没有java实现. 后面一通查询查找,才知道 如下图 native是一个java调用c语言来实现的操作的 ...
- C#开发微信公众平台-就这么简单(附Demo)转载
C#开发微信公众平台-就这么简单(附Demo) 来源:https://www.cnblogs.com/xishuai/p/3625859.html#!comments 写在前面 阅读目录: 服务号和 ...
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
- 简单数学算法demo和窗口跳转,关闭,弹框
简单数学算法demo和窗口跳转,关闭,弹框demo <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&quo ...
- Maven+SpringMVC+Dubbo 简单的入门demo配置
转载自:https://cloud.tencent.com/developer/article/1010636 之前一直听说dubbo,是一个很厉害的分布式服务框架,而且巴巴将其开源,这对于咱们广大程 ...
- Android调用Jni,非常简单的一个Demo
step1:创建一个android项目 Project Name:jnitest Build Target: Android 1.6 Application Nam ...
- vue+node+es6+webpack创建简单vue的demo
闲聊: 小颖之前一直说是写一篇用vue做的简单demo的文章,然而小颖总是给自己找借口,说没时间,这一没时间一下就推到现在了,今天抽时间把这个简单的demo整理下,给大家分享出来,希望对大家也有所帮助 ...
- EasyUI+MVC+EF简单用户管理Demo(问题及解决)
写在前面 iframe-src EntityFramework版本 connectionStrings View.Action.页面跳转 EasyUI中DataGrid绑定 新增.修改和删除数据 效果 ...
随机推荐
- HTML5——Data Url生成
HTML5——Data Url生成 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- 《剑指offer》-左旋转字符串
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S="abc ...
- 状压dp-----三进制
三进制的状压dp要先预处理3^n以及每一个数的每一位 例题 hdu3001 题意: 给定n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次. 题解: 看代码吧 ...
- 《Gradle权威指南》--Android Gradle NDK支持
No1: 在根项目下的local.properties文件中配置 sdk.dir=/home/frame/android/android-sdk ndk.dir=/home/frame/android ...
- Docker启动mysql的坑2
正确启动mysql: docker run -p 3306:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -d mysql 此时虽然启动成功.但是 ...
- [洛谷P2123]皇后游戏
很抱歉,这个题我做的解法不是正解,只是恰巧卡了数据 目前数据已经更新,这个题打算过一段时间再去写. 目前在学习DP,这个会暂时放一放,很抱歉 这个题是一个国王游戏的变形(国王游戏就把我虐了qwq) 题 ...
- Alpha冲刺随笔二:第二天
课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(十天冲刺) 团队名称:葫芦娃队 作业目标:在十天冲刺里对每天的任务进行总结. 随笔汇总:https://www.cnblogs ...
- C# JSON帮助类(可互转)
public class JsonHelper { public JsonHelper() { // // TODO: Add constructor logic here // } /// < ...
- Lakeshore 中文开发界面,示例项目,飞机大战 等 Lakeshore Chinese development interface, sample project, aircraft war, etc
Lakeshore 中文开发界面,示例项目,飞机大战 等 Lakeshore Chinese development interface, sample project, aircraft war, ...
- [BZOJ2879][NOI2012]美食节(费用流)
设sm为所有p之和,套路地对每道菜建一个点,将每个厨师拆成sm个点,做的倒数第i道菜的代价为time*i. S向每道菜连边<0,p[i]>(前者为代价后者为流量),i菜到j厨师的第k个点连 ...