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的更多相关文章

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

    一.前言 在空闲之余,学学新东西 二.服务端的代码编写与部署 这里采取的方式是MVC+EF返回Json数据,(本来是想用Nancy来实现的,想想电脑太卡就不开多个虚拟机了,用用IIS部署也好) 主要是 ...

  2. mac实现jni的demo

    今天在看ArrayList 源码时看到了System.arraycopy 这个方法,但是这个方法没有java实现. 后面一通查询查找,才知道 如下图 native是一个java调用c语言来实现的操作的 ...

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

    C#开发微信公众平台-就这么简单(附Demo)  来源:https://www.cnblogs.com/xishuai/p/3625859.html#!comments 写在前面 阅读目录: 服务号和 ...

  4. 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 ...

  5. 简单数学算法demo和窗口跳转,关闭,弹框

     简单数学算法demo和窗口跳转,关闭,弹框demo <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&quo ...

  6. Maven+SpringMVC+Dubbo 简单的入门demo配置

    转载自:https://cloud.tencent.com/developer/article/1010636 之前一直听说dubbo,是一个很厉害的分布式服务框架,而且巴巴将其开源,这对于咱们广大程 ...

  7. Android调用Jni,非常简单的一个Demo

    step1:创建一个android项目       Project Name:jnitest       Build Target: Android 1.6       Application Nam ...

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

    闲聊: 小颖之前一直说是写一篇用vue做的简单demo的文章,然而小颖总是给自己找借口,说没时间,这一没时间一下就推到现在了,今天抽时间把这个简单的demo整理下,给大家分享出来,希望对大家也有所帮助 ...

  9. EasyUI+MVC+EF简单用户管理Demo(问题及解决)

    写在前面 iframe-src EntityFramework版本 connectionStrings View.Action.页面跳转 EasyUI中DataGrid绑定 新增.修改和删除数据 效果 ...

随机推荐

  1. python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)

     先来回顾一下昨天的内容 黏包现象粘包现象的成因 : tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制 无边界 所有在连接建立的基础上传递的数据之间没有界限 收发消息很有可能不完全相 ...

  2. python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)

    一.函数名应用 函数名是什么?函数名是函数的名字,本质:变量,特殊的变量. 函数名(),执行此函数. python 规范写法 1. #后面加一个空格,再写内容,就没有波浪线了. 2.一行代码写完,下面 ...

  3. 集合Arraylist的方法的使用和打印

    package chapter090; import java.util.ArrayList;import java.util.List; public class TestList01 { publ ...

  4. whiledo循环输出9-0

    var i=9 while(i>-1){ println(i); i--; } function println(a) { document.write(a+"<br>&q ...

  5. 《剑指offer》-找到字符串中第一个只出现一个的字符

    题目描述 请实现一个函数用来找出字符流中第一个只出现一次的字符.例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g".当从该字符流中读出 ...

  6. 云平台Linux主机安装流程

    ==一.安装包===================================================================================如果是1+2主机安装 ...

  7. python全栈开发day38-css三种引入方式、基础选择器、高级选择器、补充选择器

    一.昨日内容回顾 div:分割整个网站,很多块 (1)排版标签 (2)块级标签 独占一行 可以设置高和宽,如果不设置宽高,默认是父盒子的宽 span: (1) 小区域 (2)文本标签 (3)在一行内显 ...

  8. 【noip模拟赛10】奇怪的贸易 高精度

    描述 刚结束了CS战斗的小D又进入了EVE的游戏世界,在游戏中小D是一名商人,每天要做的事情就是在这里买东西,再运到那里去卖.这次小D来到了陌生的X星,X星上有n种货物,小D决定每种都买走一些,他用a ...

  9. 练习|Django-单表

    结构目录 页面展示: 1创建Django,创建app01 在modules.py添加 class Book(models.Model): id=models.AutoField(primary_key ...

  10. PopupWindow分享页面

    效果图 步骤: 1.布局中添加分享按钮 2.画出分享页面 3.设置分享页面animator进出动画,并在style.xml中配置 4.MainActivity中添加方法 *画出布局 主页面: < ...