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. Django 关闭Debug后使用Nginx做静态文件的访问

    Django 关闭Debug后使用Nginx做静态文件的访问 关闭Django 的Debug参数 1 . 修改settings.py配置文件 DEBUG = False 2 . settings.py ...

  2. 《剑指offer》青蛙跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 很裸的斐波那契数列. class Solution { public: int jumpFloor ...

  3. hdu 1385 Floyd 输出路径

    Floyd 输出路径 Sample Input50 3 22 -1 43 0 5 -1 -122 5 0 9 20-1 -1 9 0 44 -1 20 4 05 17 8 3 1 //收费1 3 // ...

  4. poj 1789 每个字符串不同的字母数代表两个结点间的权值 (MST)

    题目大意是就是给出n个长度为7的字符串,每个字符串代表一个车,定义车的距离是两个字符串间不同字母的个数,题目要求的数不同的车的距离的最小值,即所求的就是最小生成树 Sample Input 4aaaa ...

  5. 知识点:从迭代器一直撸到yield from

    最近在跟一个系列, 难度和篇幅比较合适我这样的懒人. 敲下代码,作下注释,看看输出,就蛮好. https://www.cnblogs.com/wongbingming/p/9095243.html i ...

  6. ahoi2009维护序列

    链接:https://www.luogu.org/problemnew/show/P2023 裸的线段树维护+* 代码: #include <bits/stdc++.h> using na ...

  7. VMware 获取该虚拟机的所有权失败

    1. 虚拟机打开失败 VMware Workstation报错(打开虚拟机时出错:获取该虚拟机的所有权失败.主机上的某个应用程序正在使用该虚拟机.配置文件:D:\Ubuntu 16.04\Ubuntu ...

  8. windows server 2003 安全加固(二)

    windows server 2003 安全加固 关闭默认端口 我们知道远程桌面服务端口默认开启在3389端口,如果我们一定要用到,最好能换到另外的端口上,放到靠后的端口号上去,比如10001. 更改 ...

  9. P1356 数列的整数性

    P1356 数列的整数性打的骗分,在多组数据的情况下还能骗到分,可以了.又TMD是dp.f[i][j]表示+-第i个数能否达到%p后的余数j,如果f[n][0]==true就可以. #include& ...

  10. 进程描述和控制(os 笔记二)

    进程描述和控制 ​ 计算机最初的主要任务之一就是高效的自动化我们的工作,完成用户交付的任务.而这种任务在计算机中的表示就是一个个的进程.从上一篇文章中描述的计算机的发展历史我们能发现,无论是单道批处理 ...