java类sample是公共的_应在名samle.java的文件_Andoid NDK编程 1 - 注册native函数

打算对Android的NDK的开发做一总结,首先是JNI部分,接下来是NDK的内容。今天首先介绍一下JNI的第一部分:注册native函数。

当java代码中执行native的代码时候,首先是通过一定的方法来找到这些native方法。而注册native函数的具体方法的不同,会导致系统在运行时采用不同的方式来寻找这些native方法。

JNI有如下两种注册native方法的途径:静态和动态。其中:

静态:先由Java得到本地方法的声明,然后再通过JNI实现该声明方法。

动态:先通过JNI重载JNI_OnLoad()实现本地方法,然后直接在Java中调用本地方法。

静态注册

根据函数名找到对应的JNI函数:Java层调用函数时,会从对应的JNI中寻找该函数,如果没有就会报错,如果存在则会建立一个关联联系,以后在调用时会直接使用这个函数,这部分的操作由虚拟机完成。

静态方法就是根据函数名来遍历java和jni函数之间的关联,而且要求jni层函数的名字必须遵循

特定的格式。

具体的实现很简单,首先在java代码中声明native函数,然后通过javah来生成native函数的具体形式,接下来在JNI代码中实现这些函数即可。

看个例子就更明了了:

Java层:

static {

System.loadLibrary("samplelib_jni");

registerNatives();

}

private native void nativeFunc1();

private native void nativeFunc2();

private native void nativeFunc3();

接下来通过javah来产生jni代码声明:

假设你的java文件的包名是com.jni.samle 而类名是JniSample。

javah -d ./jni/ -classpath /Users/YOUR_NAME/Library/Android/sdk/platforms/android-21/android.jar:../../build/intermediates/classes/debug/ com.jni.samle.JniSample

然后就会得到一个JNI的.h文件,里面包含这几个native函数的声明,观察一下文件名以及函数名,会有一定的规律,我会在下一篇文章中对此做一详细介绍,在此不再赘述。

最后实现jni层的native方法即可。

动态注册

对Java程序员来说,可能我们总是会遵循:1.编写带有native方法的Java类;—->2.使用javah命令生成.h头文件;—->3.编写代码实现头文件中的方法,这样的标准流程,但也许有人无法忍受那“丑陋”的方法名称,所以我们可以采用动态注册方法,也就是通过RegisterNatives方法把c/c++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。

JNI 允许你提供一个函数映射表,注册给Jave虚拟机,这样Jvm就可以用函数映射表来调用相应的函数,

就可以不必通过函数名来查找需要调用的函数了。

Java与JNI通过JNINativeMethod的结构来建立联系,它在jni.h中被定义,其结构内容如下:

typedef struct {

const char* name;

const char* signature;

void* fnPtr;

} JNINativeMethod;

第一个变量name是Java中函数的名字。

第二个变量signature,用字符串是描述了函数的参数和返回值

第三个变量fnPtr是函数指针,指向C函数。

当java通过System.loadLibrary加载完JNI动态库后,紧接着会查找一个JNI_OnLoad的函数,如果有,就调用它, 而动态注册的工作就是在这里完成的。

一起来看一下具体的实现方法:

Java code:

比较简单,仅仅是加载so库。

static {

System.loadLibrary("samplelib_jni");

}

JNI code:

在JNI中实现

jint JNI_OnLoad(JavaVM* vm, void* reserved)

并且在这个函数里面去动态的注册native方法,完整的参考代码如下:

#include

#include "Log4Android.h"

#include

#include

using namespace std;

#ifdef __cplusplus

extern "C" {

#endif

static const char *className = "com/zhixin/jnisample/JniManager";

static void sayHello(JNIEnv *env, jobject, jlong handle) {

LOGI("JNI", "native: say hello ###");

}

static JNINativeMethod gJni_Methods_table[] = {

{"sayHello", "(J)V", (void*)sayHello},

};

static int jniRegisterNativeMethods(JNIEnv* env, const char* className,

const JNINativeMethod* gMethods, int numMethods)

{

jclass clazz;

LOGI("JNI","Registering %s natives\n", className);

clazz = (env)->FindClass( className);

if (clazz == NULL) {

LOGE("JNI","Native registration unable to find class '%s'\n", className);

return -1;

}

int result = 0;

if ((env)->RegisterNatives(clazz, gJni_Methods_table, numMethods) < 0) {

LOGE("JNI","RegisterNatives failed for '%s'\n", className);

result = -1;

}

(env)->DeleteLocalRef(clazz);

return result;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved){

LOGI("JNI", "enter jni_onload");

JNIEnv* env = NULL;

jint result = -1;

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

return result;

}

jniRegisterNativeMethods(env, className, gJni_Methods_table, sizeof(gJni_Methods_table) / sizeof(JNINativeMethod));

return JNI_VERSION_1_4;

}

#ifdef __cplusplus

}

#endif

比较

下面我们来比较一下这两种不同的实现方法。

首先是静态方法:

优点实现起来比较简单,直接用javah就能将Java代码中的native函数的声明转化为native代码的函数。

缺点在于:javah生成的jni层函数特别长;

初次调用native函数时要根据名字搜索对应的jni层函数来建立关联联系,这样影响效率。

而动态方法的优缺点刚好和静态方法相反。

通过上面的介绍我们发现,尽管静态注册实现起来比较简单,但是会导致效率相对来说比较低。

所以在JNI层提供JNI_OnLoad是一个推荐的做法。如果不提供JNI_OnLoad,那么JNI函数的命名就需要符合规范,并且需要导出该函数。这样做很容易被别人反编译。相反,如果提供JNI_OnLoad,就可以在里面自己注册JNI函数给Dalvik VM,这样JNI函数的命名就可以按照自己的习惯了,而且也不用导出。

一个巧妙的合作

在实际的应用中,我们可以巧妙的将静态注册和动态注册结合起来:也就是在java代码中仍然声明一个native函数,但是这个函数仅仅是用来去触发在JNI层的native函数的动态注册。说的有些绕,看看代码就明白了:

Java层:

static {

System.loadLibrary("samplelib_jni");

registerNatives();

}

private static native void registerNatives();

JNI层:

通过javah生成java层声明的native函数的文件,并且在实现代码中去动态注册JNI函数:

JNIEXPORT void JNICALL Java_com_zhixin_jni_JniSample_registerNatives

(JNIEnv *env, jclass clazz){

(env)->RegisterNatives(clazz, gJni_Methods_table, sizeof(gJni_Methods_table) / sizeof(JNINativeMethod));

}

后续

关于JNI的函数注册就到这里了,在下一篇文章中会总结JNI的签名规则问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF Canvas 平滑笔迹

WPF Canvas 平滑笔迹控件名&#xff1a;CanvasHandWriting作者&#xff1a;小封&#xff08;邝攀升&#xff09;原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers编辑&#xff1a;驚鏵完整的思路如下收集路径点集。平均采样路径点集。将路径点集转为…

IIS应用程序池相关问题及连接池已满的解决方法

关于应用程序池 在 IIS 6.0 中,引入了应用程序池&#xff0c;应用程序池是将一个或多个应用程序链接到一个或多个工作进程集合的配置。因为应用程序池中的应用程序与其他应用程序被工作进程边界分隔&#xff0c;所以某个应用程序池中的应用程序不会受到其他应用程序池中应用程序…

echo -n 和echo -e 参数意义

echo -n 不换行输出 $echo -n "123" $echo "456" 12最终输出 123456而不是 123 456 123456echo -e 处理特殊字符 若字符串中出现以下字符&#xff0c;则特别加以处理&#xff0c;而不会将它当成一般文字输出&#xff1a; \a 发出警告声&#xff1b; \b 删…

NetSpeed

NetSpeed公司提供的NOC包括三部分&#xff0c;可以通过NocStudio进行配置生成。 1)NetSpeed Orion&#xff0c;面向快速SoC design的可综合平台。 2)Linley NetSpeed NoC面向复杂的interconnect实现&#xff0c;同时优化内部physical implementation和timing closure. NoC是基于…

js ajax java传参_ajax参数传递与后台接收

ajax参数传递与后台接收Servlet中读取http参数的方法Enumeration getParameterNames() 返回一个 String 对象的枚举&#xff0c;包含在该请求中包含的参数的名称String getParameter(String name) 以字符串形式返回请求参数的值&#xff0c;或者如果参数不存在则返回 null。Str…

init 访问器只能初始化时赋值,是真的吗?

前言C# 提供的 init 关键字用于在属性中定义访问器方法&#xff0c;可以让属性仅能在对象初始化的时候被赋值&#xff0c;其他时候只能为只读属性的形式。例如下面代码可以正常执行&#xff1a;public class Demo {public string Name { get; init; } }var demo new Demo { Na…

eclipse实现代码块折叠-类似于VS中的#region……#endregion

背 景 刚才在写代码的时候&#xff0c;写了十几行可以说是重复的代码&#xff1a; 如果整个方法或类中代码多了&#xff0c;感觉它们太TM占地方了&#xff0c;给读者在阅读代码上造成很大的困难&#xff0c;于是想到能不能把他们“浓缩”成一行&#xff0c;脑子里第一个闪现出的…

添加Chrome插件(Github上下载的压缩文件)

首先把压缩包解压到某个文件夹 然后按照以下步骤进行即可&#xff1a; 点击Chrome浏览器上的设置->扩展程序->开发者模式->点击加载已解压的压缩文件->选中解压过的文件夹确定即可。转载于:https://www.cnblogs.com/yijianzhongqing/p/6277838.html

java定义基础变量语句_java语言基础-变量

一丶变量的基本概念1.什么是变量(1).内存中的一个存储区域(2).该区域有自己的名称(变量名),和类型(数据类型)(3.)该区域的数据可以在同一类型范围内不断变化(定义变量的主要目的是因为数据的不确定性)2.为什么要定义变量用来不断存放同一类型的常量&#xff0c;并可以重复使用3…

C# WPF MVVM模式[经典]案例

01—前言Caliburn.Micro(简称CM)一经推出便备受推崇&#xff0c;作为一款MVVM开发模式的经典框架&#xff0c;越来越多的受到wpf开发者的青睐.我们看一下官方的描述&#xff1a;Caliburn是一个为Xaml平台设计的小型但功能强大的框架。Micro实现了各种UI模式&#xff0c;用于解决…

shell数组

定义数组[rootwy shell]# a(1 2 3 4)显示数组[rootwy shell]# echo ${a[]}1 2 3 4[rootwy shell]# echo ${a[*]}1 2 3 4显示数组中的某个元素[rootwy shell]# echo ${a[0]}1增加元素[rootwy shell]# a[4]9[rootwy shell]# echo ${a[*]}1 2 3 4 9修改元素值 [rootwy shell]# a[2…

java二级程序题两个角度_两个角度图_【SCME大一】使用JAVA语言深入理解程序逻辑答案_学小易找答案...

【填空题】《蝶恋花 伫倚危楼风细细 》的作者( )。【简答题】简要概述问卷调查的整体设计?【填空题】父母在,( ),游必有方。【填空题】白居易与刘禹锡并称“( )”。【填空题】白居易,字( )。【填空题】白居易,是唐代伟大的( )主义诗人。【单选题】《红楼梦》最成功处在于塑造了…

LINUX中常用操作命令

LINUX中常用操作命令 引用&#xff1a;http://www.daniubiji.cn/archives/25 Linux简介及Ubuntu安装 常见指令系统管理命令打包压缩相关命令关机/重启机器Linux管道Linux软件包管理vim使用用户及用户组管理文件权限管理Linux简介及Ubuntu安装 Linux&#xff0c;免费开源&#x…

Log4j编写

来自: http://www.blogjava.net/zJun/archive/2006/06/28/55511.html Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的&#xff0c;它可接keyvalue格式的设置或xml格式的设置信息。通过配置&#xff0c;可以创建出Log4J的运行环境。1. 配置文件L…

C# 为什么高手喜欢用StartsWith而不是Substring进行字符串匹配?

字符串的截取匹配操作在开发中非常常见&#xff0c;比如下面这个示例&#xff1a;我要匹配查找出来字符串数组中以“abc”开头的字符串并打印&#xff0c;我下面分别用了两种方式实现&#xff0c;代码如下&#xff1a;using System;namespace ConsoleApp23 {class Program{stat…

Nginx 服务器开启status页面检测服务状态

原文&#xff1a;http://www.cnblogs.com/hanyifeng/p/5830013.html 一、Nginx status monitor 和apache 中服务器状态一样。输出的内容如&#xff1a; 第1列&#xff1a; 当前与http建立的连接数&#xff0c;包括等待的客户端连接&#xff1a;2第2列&#xff1a;接受的客户端连…

elif是不是java关键字_C# 中的#if、#elif、#else、#endif等条件编译符号 (转载)

这些是C#中的条件编译符号。这些指令我在项目中遇到过&#xff0c;查过网络&#xff0c;问过人(当然&#xff0c;既不认识大牛&#xff0c;也不认识小牛&#xff0c;所以没什么收获)。今天翻看一本资料&#xff0c;有提到这个方面的东西&#xff0c;所以写下来和能看到这篇文章…

从零开始React项目架构(四)

前言 使用当前的webpack配置能不能打包构建项目呢&#xff1f;当然可以&#xff0c;但这不是我们想要的&#xff0c;所以&#xff0c;让我们来看一看生产环境需要怎么配置webpack吧 开发 生产环境配置 在根目录创建webpack.pro.config.jsconst path require(path) const webpa…

在OpenCloudOS 上安装.NET 6

开源操作系统社区 OpenCloudOS 由腾讯与合作伙伴共同倡议发起&#xff0c;是完全中立、全面开放、安全稳定、高性能的操作系统及生态。OpenCloudOS 沉淀了多家厂商在软件和开源生态的优势&#xff0c;继承了腾讯在操作系统和内核层面超过10年的技术积累&#xff0c;在云原生、稳…

Linux 命令详解(二)awk 命令

AWK是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。之所以叫AWK是因为其取了三位创始人 Alfred Aho&#xff0c;Peter Weinberger, 和 Brian Kernighan 的Family Name的首字符。 语法&#xff1a; awk [选项参数] script varvalue file(s) 或 awk [选项参数] …