Android NDK开发之Jni调用Java对象
https://my.oschina.net/zhiweiofli/blog/114064
通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。
函数 | 描述 |
GetFieldID | 得到一个实例的域的ID |
GetStaticFieldID | 得到一个静态的域的ID |
GetMethodID | 得到一个实例的方法的ID |
GetStaticMethodID | 得到一个静态方法的ID |
构造一个Java对象的实例
jclass cls = (*env)->FindClass(env, "Lpackagename/classname;"); //创建一个class的引用
jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V"); //注意这里方法的名称是"",它表示这是一个构造函数,而且构造参数是double型的
jobject obj = (*env)->NewObjectA(env, cls, id, args); //获得一实例,args是构造函数的参数,它是一个jvalue*类型。
首先是获得一个Java类的class引用 (*env)->FindClass(env, "Lpackagename/classname;"); 请注意参数:Lpackagename/classname; ,L代表这是在描述一个对象类型,packagename/classname是该对象耳朵class路径,请注意一定要以分号(;)结束!
然后是获取函数的id,jmethodID id = env->GetMethodID(cls, "", "(D)V"); 第一个是刚刚获得的class引用,第二个是方法的名称,最后一个就是方法的签名了
还是不懂?我曾经如此,请接着看...
难理解的函数签名
JNINativeMethod的定义如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。
其中比较难以理解的是第二个参数,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
那其他情况呢?请查看下表:
类型
|
符号 |
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | L |
float | F |
double | D |
void | V |
object对象 | LClassName; L类名; |
Arrays |
[array-type [数组类型
|
methods方法 | (argument-types)return-type (参数类型)返回类型 |
稍稍补充一下:
1、方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则
比如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为"Lcom /nedu/jni/helloword/Student;"
2、方法参数或者返回值为数组类型时,请前加上[
例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[

在本地方法中调用Java对象的方法
1、获取你需要访问的Java对象的类:
jclass cls = (*env)->GetObjectClass(env, obj); // 使用GetObjectClass方法获取obj对应的jclass。
jclass cls = (*env)->FindClass(“android/util/log”) // 直接搜索类名,需要是static修饰的类。
2、获取MethodID:
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V"); //GetStaticMethodID(…),获取静态方法的ID使用GetMethdoID方法获取你要使用的方法的MethdoID
其参数的意义:
env-->JNIEnv
cls-->第一步获取的jclass
"callback"-->要调用的方法名
"(I)V"-->方法的Signature, 签名同前面的JNI规则。
3、调用方法:
(*env)->CallVoidMethod(env, obj, mid, depth);// CallStaticIntMethod(….) , 调用静态方法
使用CallVoidMethod方法调用方法。参数的意义:
env-->JNIEnv
obj-->通过本地方法穿过来的jobject
mid-->要调用的MethodID(即第二步获得的MethodID)
depth-->方法需要的参数(对应方法的需求,添加相应的参数)
注:这里使用的是CallVoidMethod方法调用,因为没有返回值,如果有返回值的话使用对应的方法,在后面会提到。
CallVoidMethod CallStaticVoidMethod
CallIntMethod CallStaticVoidMethod
CallBooleanMethod CallStaticVoidMethod
CallByteMethod CallStaticVoidMethod
现在稍稍明白文章开始构造Java对象那个实例了吧?让我们继续深入一下:
Jni操作Java的String对象
从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char*不同,所以如果你直接当做char*使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char*,这里使用JNIEnv提供的方法转换。
const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
(*env)->ReleaseStringUTFChars(env, jstr, str);
这里使用GetStringUTFChars方法将传进来的prompt(jstring类型)转换成为UTF-8的格式,就能够在本地方法中使用了。
注意:在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出。
下面是Jni访问String对象的一些方法:
- GetStringUTFChars 将jstring转换成为UTF-8格式的char*
- GetStringChars 将jstring转换成为Unicode格式的char*
- ReleaseStringUTFChars 释放指向UTF-8格式的char*的指针
- ReleaseStringChars 释放指向Unicode格式的char*的指针
- NewStringUTF 创建一个UTF-8格式的String对象
- NewString 创建一个Unicode格式的String对象
- GetStringUTFLength 获取UTF-8格式的char*的长度
- GetStringLength 获取Unicode格式的char*的长度
下面提供两个String对象和char*互转的方法:
/* c/c++ string turn to java jstring */
jstring charToJstring(JNIEnv* env, const char* pat)
{
jclass strClass = (*env)->FindClass(env, "java/lang/String");
jmethodID ctorID = (*env)->GetMethodID(env, strClass, "", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));
(*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = (*env)->NewStringUTF(env, "UTF-8");
return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);
}
/* java jstring turn to c/c++ char* */
char* jstringToChar(JNIEnv* env, jstring jstr)
{
char* pStr = NULL;
jclass jstrObj = (*env)->FindClass(env, "java/lang/String");
jstring encode = (*env)->NewStringUTF(env, "utf-8");
jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);
jsize strLen = (*env)->GetArrayLength(env, byteArray);
jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);
if (jBuf > 0)
{
pStr = (char*)malloc(strLen + 1);
if (!pStr)
{
return NULL;
}
memcpy(pStr, jBuf, strLen);
pStr[strLen] = 0;
}
env->ReleaseByteArrayElements(byteArray, jBuf, 0);
return pStr;
}
本文转自Zhiweiofli's Blog,转载请注明出处,谢谢。
Android NDK开发之Jni调用Java对象的更多相关文章
- Android NDK开发之C调用Java及原生代码断点调试(二)
上一篇中,我们主要学习了Java调用本地方法,并列举了两大特殊实例来例证我们的论据,还没学习的伙伴必须先去阅读下,本次的学习是直接在上一篇的基础上进行了.点击:Android NDK开发之从Java与 ...
- Android NDK开发之Jni的数据类型
在前面的一篇博客<Android NDK开发简介>,我简单地说明了Android NDK开发的流程,以及其重要的一环:JNI层得开发.今天我再详细说明一下自己的学习经验. JNI是Java ...
- android webView开发之js调用java代码示例
1.webView设置 webView.getSettings().setJavaScriptEnabled(true);//设置支持js webView.addJavascriptInterface ...
- Android NDK开发之从Java与C互调中详解JNI使用(一)
生活 这一个礼拜过得真的是苦不堪言,上周因为打球脚踝直接扭伤,肿的想猪蹄一样,然后休息几天消肿了,可以缓慢龟速的行走了,然而五一回来上班第一天,上班鞋子还能穿上,下班脚已插不进鞋子里面了,好吧,又肿回 ...
- Android NDK开发之Android.mk文件
Android NDK开发指南---Android.mk文件 博客分类: Android NDK开发指南 Android.mk文件语法详述 介绍: ------------ 这篇文档是用来描述你的 ...
- Android开发之JNI(一)--HelloWorld及遇到的错误解析
Android开发之JNI(一)--HelloWorld及遇到的错误解析 1.NDK环境搭建 參考http://blog.csdn.net/xiaoliouc/article/details/8 ...
- Android混合开发之WebViewJavascriptBridge实现JS与java安全交互
前言: 为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与j ...
- Android混合开发之WebView与Javascript交互
前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...
- Android安全开发之WebView中的地雷
Android安全开发之WebView中的地雷 0X01 About WebView 在Android开发中,经常会使用WebView来实现WEB页面的展示,在Activiry中启动自己的浏览器,或者 ...
随机推荐
- HTML图片元素(标记)
<html> <head> <title>第一个网页</title> </head> <body> ************** ...
- HDU3157 Crazy Circuits(有源汇流量有上下界网络的最小流)
题目大概给一个电路,电路上有n+2个结点,其中有两个分别是电源和负载,结点们由m个单向的部件相连,每个部件都有最少需要的电流,求使整个电路运转需要的最少电流. 容量网络的构建很容易,建好后就是一个有源 ...
- BestCoder#16 A-Revenge of Segment Tree
Revenge of Segment Tree Problem Description In computer science, a segment tree is a tree data struc ...
- Prerequisites?[HDU1144]
Prerequisites?Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- ccc 播放动画
cc.Class({ extends: cc.Component, properties: { anim:cc.Animation, }, // use this for initialization ...
- 【转】敏捷开发 Scrum 总结
转:http://www.open-open.com/lib/view/open1330413325514.html 最近把之前学习 Scrum 的资料整理为一篇文档,在接下来的团队和项目开发中,根据 ...
- 桌面每日一句--桌面翻译工具(有道翻译,微软翻译,Google翻译)
现在的翻译软件功能越来越多,也越来越臃肿,还不时弹广告,真的很烦恼. 鉴于这种情况,自己做了个翻译软件,能满足日常需求就好了.需要用的时候可以直接在桌面输入单词翻译,或者直接使用快捷键呼出翻译窗口.最 ...
- leetcode Container With Most Water
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). ...
- Android -- TabHost
TabHost 也就相当于Windows下的选项框 有两种实现方式 1. 继承TabActivity (已经废弃):从TabActivity中用getTabHost()方法获取TabHost 2. ...
- spring源码学习之路---IOC实现原理(三)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章我们已经初步认识了Be ...