Android中关于JNI 的学习(四)简单的例子,温故而知新

Android安卓中jni封装代码打包为aar 前文已经介绍jni编译c++代码且已经成功封装成java,但是c++是以源代码形式继承在app中,本文介绍如何将前述jni c++代码以隐藏源代码封装成aar的形式。 阅读详情

在第零篇文章简单地介绍了JNI编程的模式之后,后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我到底说的清楚没有,但相信很多童鞋跟我一样,在刚开始学习一个东西的时候,入门最好的方式就是一个现成的例子来参考,慢慢研究,再学习概念,再回过来研究代码,加深印象,从而开始慢慢掌握。

今天我们就再来做一个小Demo,这个例子会比前面稍微复杂一点,但是如果阅读过前面几篇文章的话,理解起来也还是很简单的。很多东西就是这样,未知的时候很可怕,理解了就很简单了。

1)我们首先定义一个Java类,里面包含几个native方法,如下:

public class ParamTransferTest {

	public static int testval = 1;
	
	public native void changeTestVal();
	
	public native int add(int x, int y);
	
	public native String addTail(String tail);
	
	public native int[] changeArray(int[] arr);
}

2)利用javah工具生成对应的头文件,如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lms_jni_ParamTransferTest */

#ifndef _Included_com_lms_jni_ParamTransferTest
#define _Included_com_lms_jni_ParamTransferTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    changeTestVal
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_lms_jni_ParamTransferTest_changeTestVal
  (JNIEnv *, jobject);

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_lms_jni_ParamTransferTest_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    addTail
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_lms_jni_ParamTransferTest_addTail
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    changeArray
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_com_lms_jni_ParamTransferTest_changeArray
  (JNIEnv *, jobject, jintArray);

#ifdef __cplusplus
}
#endif
#endif

上面就生成了对应的方法,在上面我们可以看到前面文章所介绍过的方法名称以Java开头,方法签名等信息,对吧。

3)编写 C 文件,如下:

#include <stdio.h>
#include <stdlib.h>
#include "com_lms_jni_ParamTransferTest.h"
#include <android/log.h>
#include <jni.h>
#include <malloc.h>

#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

char* Jstring2CStr(JNIEnv * env, jstring str){
	char * rtn = NULL;

	jclass clsstring = (*env)->FindClass(env, "java/lang/String");//通过FindClass方法获得Java的String类
	jstring strencode = (*env)->NewStringUTF(env, "UTF-8");//调用NewStringUTF方法,获得"UTF-8"字符串,作为编码
	jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");//获取String类的getBytes方法
	jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, str, mid, strencode);//调用String类的getBytes方法

	jsize alen = (*env)->GetArrayLength(env, barr);//获得数组长度
	jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);//获得数组的首地址,C/C++中数组的首元素就是一个指针
	if(alen > 0){
		rtn = (char*) malloc(alen + 1);
		memcpy(rtn, ba, alen);
		rtn[alen] = 0;
	}//上面这一步是将数组的值复制到一个char*的数组中,也就是C/C++的char数组,因为C/C++没有字符串概念,最后以0结尾。
	(*env)->ReleaseByteArrayElements(env, barr, ba, 0);//释放内存
	return rtn;
}

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    changeTestVal
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_lms_jni_ParamTransferTest_changeTestVal
  (JNIEnv * env, jobject obj){
	jclass clazz = (*env)->GetObjectClass(env,obj);//获得obj对应的类,也就是ParamTransferTest
	jint val = (*env)->GetStaticIntField(env, clazz,
						(*env)->GetStaticFieldID(env, clazz,"testval","I"));//获取字段testval的值
	LOGI("before change testval = %d", val);//添加Log信息
	val = val + 1;
	LOGI("after change testval = %d", val);
	(*env)->SetStaticIntField(env, clazz,(*env)->GetStaticFieldID(env, clazz,"testval","I"),val);//设置字段testval的值
}

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_lms_jni_ParamTransferTest_add
  (JNIEnv * env, jobject obj, jint x, jint y){
	LOGI("x = %d", x);
	LOGI("y = %d", y);
	return x + y;       //返回参数x和y的和
}

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    addTail
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_lms_jni_ParamTransferTest_addTail
  (JNIEnv * env, jobject obj, jstring str){

	char* p = Jstring2CStr(env,str);//将Java中的string转化为C/C++中的char数组
	LOGI("str = %s", p);
	char* newStr = " Tail ";
	return (*env)->NewStringUTF(env, strcat(p, newStr));//调用strcat函数连接两个char数组,将通过NewStringUTF返回。
}

/*
 * Class:     com_lms_jni_ParamTransferTest
 * Method:    changeArray
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_com_lms_jni_ParamTransferTest_changeArray
  (JNIEnv * env, jobject obj, jintArray ja){
	int len = (*env)->GetArrayLength(env, ja);/获取数组长度
	LOGI("len = %d", len);
	LOGI("address = %#x", &ja);
	
	jint* arr = (*env)->GetIntArrayElements(env, ja, 0);//将数组中的所有元素存入以jint*为首地址的数组中(数组的首地址就是数组名)

	int i = 0;
	for(;i < len; i++){
		LOGI("arr[%d] = %d", i, *(arr + i));
		*(arr + i) += 10;
	}
    //数组中每个元素的值加上10return ja;由于GetIntArrayElements的最后一个参数是0,即表明获取的数组是不复制的,即它们操作同一块内存,所以返回哪个数组都是ok的
	return ja;
}


对应这四个方法,在上面都添加了一些注释,大家看着注释,自己研究一下逻辑,也就清楚了这几个方法实现的功能是什么,很简单的。

4)编写Android.mk文件,如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := com_lms_jni_HwDemo

LOCAL_SRC_FILES := \
HwDemo.c \
JniTest.c \
ParamTransferTest.c

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

在这里有一点的注意的是,编译多个文件的时候,要利用反斜杠 "\"来进行换行,区分不同的C/C++文件。

而这里LOCAL_LDLIBS是JNI中运用log所需要添加的动态包,下一篇文章会讲。

5)编写好Android.mk文件之后,就利用ndk-build文件进行编译,文件结构如下:



在jni目录下运行ndk-build,如下:


到这里,关于JNI层的实现就结事了,下面就是Java端的事情。

6)Activity中调用,如下:

public class HwDemo extends Activity {

	static {
		System.loadLibrary("com_lms_jni_HwDemo");//加载动态包,名称就是Android.mk中的Module名称。
	}
	
	public native String printHello();	

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);		
		setContentView(R.layout.main);
		...
		
		TextView tvAdd = (TextView)findViewById(R.id.tvAdd);
		TextView tvString = (TextView)findViewById(R.id.tvString);
		TextView tvArray = (TextView)findViewById(R.id.tvArray);
		
		TextView tvChangeTestVal = (TextView)findViewById(R.id.tvChangeTestVal);		
		ParamTransferTest ptt = new ParamTransferTest();
		//调用changeTestVa()方法
		ptt.changeTestVal();		
		tvChangeTestVal.setText("" + ptt.testval);
		
		//调用add方法
		int sum = ptt.add(1, 2);
		tvAdd.setText(String.valueOf(sum));
		//调用addTail方法
		tvString.setText(ptt.addTail("lms"));
		//调用changeArray方法
		int[] newArr = ptt.changeArray(new int[]{1,2});
		
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		sb.append(newArr[0]).append(",").append(newArr[1]);
		sb.append("]");
		tvArray.setText(sb.toString());
				
	}

}

7)结果显示:

关于如果在Java层调用JNI方法,还有在JNI层调用Java的方法,并操作Java的对象,相信经过这一个例子,再结合前面几篇文章所讲的东西,大家应该能够对JNI的作用和应用有一个比较基本的了解了。

Android中底层框架的实现,尤其是在启动的时候,Native层去加载一个系统核心服务,或者启动Zygote虚拟机的时候,用到了大量的JNI层面的框架,大家如果对JNI熟悉了解了,再去了解这些框架的东西,会有很大的帮助的。

结束。

Android应用中JNI调用实例教程 本文还有配套的精品资源,点击获取 简介:本教程深入探讨了Android应用中使用JNI进行跨语言通信的过程。通过实例“android调用JNI实例”,介绍了创建Android项目、配置NDK、编写JNI接口、生成头文件、Java层调用JNI以及构建和运行应用的完整步骤。教程还强调了不同平台使用NDK编译和调试的重要性,并提示了使用本地代码时需要注意的问题。 1. ... 阅读详情

相关推荐

Android学习--JNI

JNI学习

a130226123的博客 2479

Android studio JNI jni实例

1.Jni的作用   1.Jni的作用 Java是一种比较高级的语言,Java调用c库,调用c++库是必不可少的,所以Jni就应运而生了。看了这个文章的同学,应该能够自己写个APK装在自己的手机里面吧,以前刚开始做android的时候,写了一个“地瓜手电筒”和一个音乐播放器。 NDK:NDK是Native Development Kit的缩写,是Google提供的一套工具集,可以让你其...

嵌入式Linux 951

Android JNI示例代码

本Android示例是java调用c语言的JNI实现,有关具体实现的细节请参见博文http://blog.youkuaiyun.com/l1028386804/article/details/47405683

Android JNI的使用方法

JNI 是Java Native Interface的缩写,表示Java本地调用,通过JNI技术可以实现Java调用C程序和C程序调用Java代码。

WenYangFF的博客 1363

android JNI简单例子

该app为android系统下简单的jni示例,是学习JNI的好例子,为入门者提供简单的JNI环境配置示例

OFDM基本原理

OFDM基础介绍,包括OFDM的核心思想,数学推导了OFDM信号的调制解调过程。

伊丽莎白的学习之路 8908

Android 使用 jni Demo示例

Android 使用JNI 基础流程

gvvbn的专栏 1764

卡尔曼滤波原理详解及系统模型建立(simulink)

卡尔曼滤波原理详解及系统模型建立(simulink) 卡尔曼滤波器 卡尔曼滤波器是在上个世界五六十年代的时候提出的,到今天已经有六十年左右的时间,但卡尔曼滤波算法不管在控制、制导、导航或者通讯方面对数据的预测能力依然处在一个不可撼动的位置上,但是很多人对于其算法内部的工作原理究竟是怎么运作的依然不理解,所以在工程上很多人都只是把卡尔曼滤波当成是一种“黑箱”预测算法,并不清楚内部原理。但实际上没有任...

weixin_43942325的博客 7万+

Android开发一个简单JNI例子

最近学习JNI为了记录一下开发过程,通过实现一个简单的jni例子来记录下开发的流程和环境配置,使用的操作系统是windows。 使用Android Studio开发当然开发环境时必须的,此外需要配置NDK的开发环境,NDK环境很简单,首先需要下载NDK包,可以自行google下载,也可以在这里下载。下载后解压,注意ndk包所放的目录路径中不能有空格,如:Program Files (x86),否...

demon的博客 2691

Python数据分析案例——宏观经济指标与沪深指数实证研究分析

沪深300指数与宏观经济指标关联性研究:2015-2024实证分析 摘要:本文基于2015-2024年月度数据,采用多元回归方法分析宏观经济指标对沪深300指数的影响。研究发现,市场情绪(SEN)、美国利率(STY)、美元指数(DXY)、狭义货币供应量(M1)和CPI对指数具有显著解释力(P<0.05),而GDP、LPR等传统指标影响不显著。模型解释力达62%(R²=0.62),表明A股短期走势更受资金流动、投资者心理和国际金融条件驱动。研究为投资者提供了除基本面外的市场预判指标,建议关注M1增速、美

weixin_50902344的博客 1404

HiCMAE 论文复现:基于 RAVDESS 数据集的音视频情感识别

多模态情感识别是人工智能领域的重要研究方向,旨在通过结合多种感知模态(如音频、视频、文本等)来更准确地识别人类情感状态。与传统单模态方法相比,多模态方法能够利用不同模态间的互补信息,提高情感识别的鲁棒性和准确性。 RAVDESS(Ryerson Audio-Visual Database of Emotional Speech and Song)是一个常用的多模态情感识别数据集,包含24位专业演员(12名男性,12名女性)表达的8种情感状态(中性、平静、快乐、悲伤、愤怒、恐惧、厌恶和惊讶)的音视频数据。

max500600的博客 497

Android Jni的介绍和简单Demo实现

JNI 全程:JNI(Java Native Interface),通俗翻译:Java本地方法官方说法:提供一种Java字节码调用C/C++的解决方案,JNI描述的是一种技术。所以这里的Nativie的本地的意思就是C/C++,所以JNI通俗理解就是Java调用C/C++的方案技术。//定义变量和方法private:int number;public://定义方法。

wenzhi的博客 3227

36、真核生物RNA PolII启动子预测相关研究

本文综述了真核生物RNA聚合酶II启动子预测的研究进展,涵盖转录调控机制、核心启动子元件(如TATA框、INR、GC框)、转录因子结合位点预测的挑战与方法。介绍了基于权重矩阵、神经网络和隐马尔可夫模型等多种启动子预测算法,并探讨了启动子分类策略及评分加权方法。通过Hertz-Stormo-Hartzell流程和基因微阵列分析实例,展示了如何识别保守调控序列。文章还总结了当前预测技术的局限性,提出了整合多组学数据、开发深度学习模型、加强实验验证等未来研究方向,旨在提升启动子识别的准确性与生物学意义。

palm99的专栏 187

Android中关于JNI 的学习(四)简单的样例,温故而知新

在第零篇文章简单地介绍了JNI编程的模式之后,后面两三篇文章。我们又针对JNI中的一些概念做了一些简单的介绍。也不知道我究竟说的清楚没有,但相信非常多童鞋跟我一样,在刚開始学习一个东西的时候,入门最好的方式就是一个现成的样例来參考。慢慢研究,再学习概念,再回过来研究代码,加深印象。从而開始慢慢掌握。 今天我们就再来做一个小Demo,这个样例会比前面略微复杂一点,可是假设阅读过前...

adr5970的博客 124

【软考中级】多媒体应用设计师复习笔记第十章【free】

第10章法律法规与标准规范 行业标准 缩写的大写拼音 地方标准 DB加生代码 企业标准Q加斜线企业代号国际标准是国际标准化组织ISO和国际电工委员会IEC制定的标准 国家标准是由国务院标准化行政主管部门制定,全国范围内使用 ?强制性国家标准的代号为GB,推荐性国家标准的代号为GB/T。 ?软件开发规范GB8566-88属于强制性国家标准 在这里插入图片描述 行业标准代号由大写汉语拼音字母组成,加上斜线和T,组成推荐性行业标准,如XX/T。已经发布的行业代号有QJ(航天),SJ(电子

weixin_47120900的博客 639

基金估值核算系统三国杀:恒生 VS 赢时胜 VS 融选!

本文对比分析了恒生电子、赢时胜和融选科技三家金融科技公司的基金估值系统。恒生电子作为行业龙头,在公募基金领域占据较大份额,其新一代估值系统6.0采用微服务架构,自动化程度高;赢时胜在中型公募和券商资管领域优势明显,其V5.5系统在信创适配和复杂产品处理方面表现突出;融选科技作为新兴厂商,提供轻量化解决方案,适合中小型机构。文章从市场格局、系统定位、技术架构、成本构成和用户反馈五个维度进行深入比较,为金融机构选型提供参考。当前估值系统市场呈现"三国鼎立"格局,各具特色,选型需结合机构规模、

magbox520的博客 825

Android中关于JNI 的学习(零)简单的例子,简单地入门

1)创建Java类文件,并定义Native方法,如JniTest类。 2)利用javac生成class文件,然后回到src目录,利用javah生成C/C++头文件,在这里要注意,javah命令要在包的根目录下调用,对应的类文件,必须是完整的类名,如下: 在Src目录:javah com.lms.jni.JniTest,在上面的截图,也可以看到javac之后,是回到src目录,再调用javah。 3)编写对应的C文件,如JniTest.c,在里面实现C/C++的方法,记得要放在jni文件夹下面。 4)编写An

持剑 2602

【WRF-Chem教程-附录B】使用 MOZART 与WRF-Chem

使用MOZART与WRF-Chem

WW、forever的博客 242

Android---简单的JNI实例

简单的JNI调用实例

格物致知的专栏 2317

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android JNI HIDL 简单实例学习

突然看到一篇文章Android HIDL学习,跟这位大神是有一面之缘的,正好也想学习Android是怎么从 APP → JNI Client → HIDL代码我已经上传到了CSND的资源,首先我们看一下结构图和代码目录吧 HIDL接口 按着开头提到的博客,常规的创建hidl文件的方法,这里也可以不用make hidl-gen,使用out目录中已经生成的一样可以用 这里要注意大神博客上提到INaruto.hal的位置可以随便放,但实际上是不可以的,必须按结构目录来放置,不然无法使用hidl-gen生成c+

Android驱动开发 2314

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

安卓studio jni 简单实例demo

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

2401_84123005的博客 696

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android中JNI编程详解

前几天在参加腾讯模拟考的时候,腾讯出了一道关于JNI的题,具体如下: JNI本身是一个非常复杂的知识,但是其实对于腾讯的这道题而言,如果你懂JNI,那么这道题会非常简单,就相当于C语言中的hello world级难度。下面就我自己翻看的一些参考书及网上的一些资料,综合自己的思考与理解,以腾讯的这道考题为例来详细讲解关于JNI的知识。 JNI是Java Native Interface的

(* ̄︶ ̄) 9911

Android JNI基础及其简单使用

Android JNI基础及其简单使用 前言:内容主要包括jni的概念、安卓jni开发的两种方式以及工具的简单使用,读者将了解最基础的jni开发流程。 主要参考:齐行超老师的教程 目录 Android JNI基础及其简单使用 一、JNI、NDK、Cmake、ndk-build的概述 二、Cmake工具的使用(Android默认) 三、ndk-build工具的使用 一、JNI、NDK、Cmake、ndk-build的概述 JNI(Java Native Interface)Java本地.

居家小男的博客 2919

利用安卓源码的例子程序编写调用JNI

在安卓工程源码的development/samples/SimpleJNI目录下,这是一个简单的JNI例子。 首先看里面的Android.mk: # # Copyright (C) 2008 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); #

Fiddle 511

Android JNI学习(四)——JNI的常用方法的中文API

JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互

Jason_Lee155的博客 1454
上一篇: Android中关于JNI 的学习(三)在JNI层访问Java端对象
下一篇: Android中关于JNI 的学习(五)在C文件中使用LogCat
linmiansheng
博客等级 码龄20年 507粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值