Android Jni开发-实战篇(CMake)
本例demo下载地址:JniDemo下载
简介
上篇介绍了Android Studio中CMake简单配置jni开发。不清楚的可以看
Android Jni开发-基础配置篇(CMake)
如果不想麻烦的话直接在示例Jni代码native-lib.cpp中添加自己的业务逻辑即可。但是这样当代码一多了的时候不好扩展也不好管理,因此这次来实践添加自己的Jni代码。
目标:
实现一个简单的jni函数sum(int a, int b),返回a+b的结果。一个稍微复杂点的jni函数twoSum(int nums[], int target),实现的是leetcode上的一个题目TwoSum,内容是给定数组及目标数字,返回符合目标数字的2个数的下标(数组类型)。
1、首先建立一个demo.h
该文件作为c++的头文件,声明要实现的函数。
#ifndef JNIDEMO_DEMO_H
#define JNIDEMO_DEMO_H#endif //JNIDEMO_DEMO_Hclass Demo{
public:Demo();int sum(int a, int b);int *twoSum(int nums[], int target);};
2、建立demo.cpp文件实现算法。
该文件实现头文件声明的函数。
#include <cstring>
#include "demo.h"Demo::Demo() {}int Demo::sum(int a, int b) {return a + b;
}int* Demo::twoSum(int nums[], int target) {int length = sizeof(nums);if (length < 2){return nullptr;}int *result = nullptr;for (int i = 0; i < length; i++){for (int j = i + 1; j < length; j++){if (nums[i] + nums[j] == target){result = new int[2];result[0] = i;result[1] = j;break;}}}return result;
}
3、创建demo-lib.cpp文件
这个文件里面放的是我们的jni代码,暂时还不用写先,因为现在不想手动写jni函数名,至于为什么叫demo-lib(.cpp文件名加-lib),一句话,官方推荐命名格式以及样例也是这样命名的。
4、修改CMakeLists.txt
跟之前native-lib文件一样,新加的库使用add_library指令。我们直接复制native-lib的add_library添加到下面,将native-lib改成我们的demo-lib.cpp(即第3点创建的jni代码文件)。
然后往连接库的指令添加这个库的声明。
至此,CMakeLists.txt的修改就完成了,就是这样简单。
5、添加java native方法接口
上篇示例中java native方法接口是直接声明在MainActivity中的,为方便管理,我们建立一个专门的Jni接口包用来管理所有的java native方法集合,为跟demo-lib.cpp对应,我们创建一个Java的Demo接口类。
这里使用Android Studio的好处就体现出来了,java native方法接口未有相应的jni函数接口是会标红提醒的,因为我们的demo-lib.cpp未添加任何代码,所以这里标红了。因此也可以根据这个来判断jni命名是否写正确,不正确的话会标红提醒。
6、编写jni函数名
为解决上面的标红提醒,我们来编写jni函数名。我们知道jni函数名是有一定格式的,不熟悉的朋友可能会觉得jni函数名很难写,但是如果熟悉了是可以直接对照java native方法手动编写对应jni代码函数,毕竟写错了也没关系,会标红提醒的。这里推荐使用java命令为我们自动生成jni代码,毕竟函数一多,手写很累的。
(1) 打开windows的cmd命令(当然也可以使用Android Studio自带的Terminal控制台),切换到Demo.java这个native 方法接口类的路径。然后使用javac Demo.java
将该类转换为.class文件。
可以发现,执行后报了一个错,这是由编码格式不对造成的,因为我们这个类的注释里面使用了中文。虽然可以更改编码格式解决,但是为了减少不必要的麻烦,最好在这个接口类中不要出现中文。我们把类里面的中文注释改成英文再试试。
可以发现,这次不报错了。
这时可以发现Demo.java的目录下多了个Demo.class文件。
(2)接着切换回工程的java目录下,使用javah -classpath . -jni + 包名 + 文件名
生成.h文件(命令中-jni前面的点是必要的)。windows切换上级目录使用cd…命令。
执行完成后,可以在java目录下看到一个以包名+文件名的.h文件,里面即写好了Demo.java对应的jni函数名称代码。
这个文件的内容如下所示:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class mhwang_com_jni_Demo */#ifndef _Included_mhwang_com_jni_Demo
#define _Included_mhwang_com_jni_Demo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: mhwang_com_jni_Demo
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_mhwang_com_jni_Demo_sum(JNIEnv *, jobject, jint, jint);/*
* Class: mhwang_com_jni_Demo
* Method: twoSum
* Signature: ([II)[I
*/
JNIEXPORT jintArray JNICALL Java_mhwang_com_jni_Demo_twoSum(JNIEnv *, jobject, jintArray, jint);#ifdef __cplusplus
}
#endif
#endif
可以看到,文件里面已经写好Demo.java里面方法相对应的jni函数名了。
(3) 这时把生成的.h文件里面的内容复制粘贴到我们之前创建的demo-lib.cpp文件里面,jni代码里面的命名部分就完成了。
当写好jni函数名后,你会发现Demo.java里面的代码也不再是红色了,说明Demo.java里面的方法能正确调用jni的函数了。
7、实现jni调用C++函数
先实现sum()这个比较简单的jni函数,我们先把函数的参数补上,然后调用demo.cpp里面的Demo对象的sum()方法进行计算。由于这里使用了demo.cpp里面的类Demo,因此需要在头文件引用demo.cpp文件。
在MainActivity调用一下,然后我们来运行一下看看:
调用成功了。接下来实现twoSum()调用。c++中的twoSum函数需要传递一个数组,而java的数组是不能直接作为参数传递给c++函数的,因此需要Jni作一层转换。具体的jni转换函数如下:
/***
* 将java的数组转成c++指针数组
* ***/
jint * getIntArrayFromJava(JNIEnv *env, jintArray j_array){jint *c_array;jint arr_len;arr_len = (*env).GetArrayLength(j_array);c_array= (jint*)malloc(sizeof(jint) * arr_len);// 初始化memset(c_array,0, sizeof(jint)*arr_len); // 此处留意// 获取数组c_array= (*env).GetIntArrayElements(j_array,NULL);return c_array;
}
这里使用了一些C++内置函数,因此需要在jni头文件中引入。
#include <cstring>
#include <malloc.h>
然后在jni函数中直接调用该函数转换成指针形式传递给C++函数中:
在MainActivity中调用:
运行结果如下:
Android Jni开发-实战篇(CMake)相关推荐
- android 串口开发第二篇:利用jni实现android和串口通信
一:串口通信简介 由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以 ...
- Android JNI开发入门与实战
简介: 涉及到一些算法或者底层驱动的时候,往往需要使用jni来开发.现在官方推荐使用CMake工具来开发jni. 使用CMake开发Jni其实挺简单的,要求不高的话只需要简单配置一下就可以使用了. 配 ...
- Android JNI开发入门之二
在上一篇文章<Android JNI开发入门之一>中,我介绍了Android应用程序(APK)怎样通过JNI调用Native C实现的共享库.本文将进一步介绍Android应用程序通过JN ...
- 《Android Studio开发实战 从零基础到App上线(第2版)》出版后记
2015年11月23日,鄙人在csdn发表了第一篇技术文章,掐指一算距今已有三年.遥想当年开写博客,只是为了总结经验同时分享出来,后来机缘巧合受到出版社编辑邀请并出了书,完全是无心插柳的结果.当初写作 ...
- 《Android Studio开发实战 从零基础到App上线》源码运行问题解答
本书提供了所有章节的完整源码下载,自上市以来陆续收到读者的意见反馈,现将与源码有关的问题汇总归类如下,方便更多的朋友解决源码运行过程中发现的问题: 一.打开本书源码时,出现"Plugin w ...
- 《Android Studio开发实战 从零基础到App上线》第一版的资源下载和内容勘误
资源下载 下面是<Android Studio开发实战 从零基础到App上线>(第一版)一书用到的工具和代码资源: 1.本书使用的Android Studio版本为2.2.3,因为Andr ...
- 《Android Studio开发实战 从零基础到App上线(第2版)》资源下载和内容勘误
资源下载 下面是<Android Studio开发实战 从零基础到App上线(第2版)>一书用到的工具和代码资源: 1.本书使用的Android Studio版本为3.2,最新的安装包可前 ...
- Android NFC开发实战详解
Android NFC开发实战详解 Android开发实战详解NFC国内第一本AndroidNFC开发书籍带你开启AndroidNFC开发的神秘之旅大综合案例帮助读者快速进入实战角色:WiFi快速连接 ...
- 微信小程序|开发实战篇之一
开发实战篇之一 前言 1.通用方法的封装 2.数据获取方法的封装 2.1 抽离classic.js中的request()方法 2.2 组件数据传递 3.movie组件的创建 3.1 组件代码开发 3. ...
- 微信小程序|开发实战篇之request请求(单个、多个参数,json对象,header)
开发实战篇之request请求 前言 1.发送单个.多个参数的request 2.发送JSON对象的request 3.发送header的request 前言 小程序发送网络请求常会遇到的问题: 请求 ...
最新文章
- LeetCode Reverse Linked List II
- ImportError: No module named babel.dates
- oracle db-link 分布式数据库网络配置协议错误,Oracle学习(18)【DBA向】:分布式数据库...
- android 字符串特殊字符转义
- linux将文件的第二列求和,awk实现第一列相乘,第二列求和,并相加 - 米扑博客...
- php camp,Byte Camp
- 线程编程(thread programming)介绍
- 卷积层、池化层和全连接层 区别和作用
- 利用Python网络爬虫抓取韩寒博客推荐第一篇(urllib的简单使用与Beautifulsoup实战,i/o编程)
- 中国智慧园区标准化白皮书 附下载
- 台式计算机睡眠快捷键,电脑如何设置快捷方式迅速进入睡眠的状态?
- 【Java】P1957 口算练习题—(洛谷OJ)
- 第一次基因数据处理从集群到数据处理结果---构建菌群物种丰度的图谱
- html让登录框3d,CSS3实现3D旋转动态显示登录注册
- css b加粗怎么用,CSS去掉b加粗和strong加粗标签样式.doc
- 识别喜欢开发的程序员
- error LNK2005: _DllMain@12 已经在 MSVCRTD.lib(dllmain.obj) 中定义
- outlook导出邮件(.msg)读取和解析
- 开发者工具绕过前端debuger
- k8s存储PV与PVC使用详解
热门文章
- 从架构设计到系统实施-基于.NET 3.0的全新企业应用之基于WCF的系统服务
- LinkedList的源码分析(基于jdk1.8)
- Inferred type 'S' for type parameter 'S' is not within its bound;
- jQuery图片预加载(延迟加载)之插件Lazy Load
- python 基础语法梳理(二)
- MVC模式在Java Web应用程序中的实现
- CROC 2016 - Elimination Round Mischievous Mess Makers
- PostgreSQL 的 window函数
- 服务器互相备份不同步_94爱分享拍了拍你,这款好用的数据同步备份软件千万不要错过!...
- python-opencv 角点检测的 FAST 算法