成功实现C/C++调用Java (Android NDK 开发)--参考1
来源:互联网 发布:网络上弧是什么意思 编辑:程序博客网 时间:2024/04/27 09:44
成功实现C/C++调用Java (Android NDK 开发)
2011-05-30 00:50:09| 分类: iPad iMac 开发|字号 订阅
用C/C++调用Java
在 java 里面写一个弹出信息对话框messagebox 是静态函数 , c++里面去调用;调用静态函数(其实就是全局函数)比成员函数方便多了。首先不需要java对象jobject,直接去找方法就ok了。。。
java 代码
.....
/*
* 显示对话框
*/
static int showMessage(String title,Stringstring)
{
new AlertDialog.Builder(g_context)
.setTitle(title)
.setMessage(string)
.setPositiveButton( "确定" ,
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialoginterface, int i){
}
}).show();
return 0;
}
native static int testCallBack(String title,Stringval);
.....
C++ (NDK) 代码:
JNIEXPORT jint JNICALLJava_com_example_hellojni_HelloJni_testCallBack(JNIEnv* env, jobjectthiz,jstring title,jstring val)
{
jclass java_class =env->FindClass("com/example/hellojni/HelloJni");
jmethodID java_method =env->GetStaticMethodID(java_class, "showMessage", "(Ljava/lang/String;Ljava/lang/String;)I");
if(java_method == 0){
return 0;
}
env->CallStaticIntMethod(java_class,java_method,title,val);
return 1;
}
-------- 注 意 ---------
第一: (Ljava/lang/String;Ljava/lang/String;)I 这个好像很重要,需要 javap工具得到:
在目录 bin/com/....下
运行 javap -s 类名称 (注意,类名称后面不用.class)
第二:c++调用函数绿色部分 env->CallStaticIntMethod(java_class,java_method,title,val); 要和 native static int testCallBack(Stringtitle,String val); 对应;
如何静态函数定义为 void 型; 那么c++中调用函数应该为CallStaticVoidMethod。 切记!!!
调用方法
// message box
btn3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//showMessage("aaa",HelloJni.this);
//showMessage("aaa");
testCallBack("aaa","bbb");//"String val");
}
});
当然,java直接调用showMessage("aaa",“b”)就可以;这样调用,相当于java调用 c++, c++再调用java, 绕了一圈,似乎多此一举;
其实不然;
c++ 肯定不是简单的调用一下java的函数;再调用的过程中会添加更多的应用。 使二者的功能结合起来。。 比如: 调用java的绘制函数,则在
c++中就可以完成绘制;
以下为网上搜查资源:个人感觉没有多大用。。。
=====================================================
转载: http://www.eoeandroid.com/thread-61684-1-1.html
document.body.oncopy = function () { if (window.clipboardData) {setTimeout(function () { var text = clipboardData.getData("text"); if(text && text.length > 300) { text = text + "\r\n\n本文来自CSDN博客,转载请标明出处:"+ location.href; clipboardData.setData("text", text); } }, 100); } }
用C/C++调用Java的方法我没有去研究,也不知道从哪里开始研究,对Linux我了解到很少,希望有朋友可以给些资料,我的水平很差,望大家多多包涵。
这个例子是别人的代码,我忘记从来里弄来的了,先对原作者表示抱歉。同时代码也被我修改过,再次道歉。
而此文和别的文章一样,只是作为我平时学习积累的验证。
1. Android.mk文件:
LOCAL_SRC_FILES参数用空格隔开
view plaincopy to clipboardprint?
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:=native
LOCAL_SRC_FILES:=geolo.cpp my_jni.h
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:=$(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:=nativeLOCAL_SRC_FILES:=geolo.cpp my_jni.h include $(BUILD_SHARED_LIBRARY)
2. geolo.cpp
先用FindClass方法找到java类,有点类似java的反射用LoadClass
再用CallObjectMethod方法调用Java类的函数。
view plaincopy to clipboardprint?
#include "my_jni.h"
jobject getInstance(JNIEnv* env, jclass obj_class){
jmethodID construction_id = env->GetMethodID(obj_class, "<init>", "()V");
jobject obj = env->NewObject(obj_class, construction_id);
return obj;
}
JNIEXPORT jstring JNICALL Java_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv* env, jobject thiz){
jstring str;
jclass java_class = env->FindClass("com/easepal/geolo/CForCall");
if (java_class == 0){
return env->NewStringUTF("not find class!");
}
jobject java_obj = getInstance(env, java_class);
if (java_obj == 0){
return env->NewStringUTF("not find java OBJ!");
}
jmethodID java_method = env->GetMethodID(java_class, "GetJavaString", "()Ljava/lang/String;");
if(java_method == 0){
return env->NewStringUTF("not find java method!");
}
str = (jstring)env->CallObjectMethod(java_obj, java_method);
return str;
}
#include "my_jni.h" jobject getInstance(JNIEnv* env, jclassobj_class){ jmethodID construction_id = env->GetMethodID(obj_class,"<init>", "()V"); jobject obj =env->NewObject(obj_class, construction_id); return obj; } JNIEXPORT jstringJNICALL Java_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv* env, jobjectthiz){ jstring str; jclass java_class =env->FindClass("com/easepal/geolo/CForCall"); if (java_class ==0){ return env->NewStringUTF("not find class!"); } jobjectjava_obj = getInstance(env, java_class); if (java_obj == 0){ returnenv->NewStringUTF("not find java OBJ!"); } jmethodID java_method =env->GetMethodID(java_class, "GetJavaString","()Ljava/lang/String;"); if(java_method == 0){ returnenv->NewStringUTF("not find java method!"); } str = (jstring)env->CallObjectMethod(java_obj,java_method); return str; }
3. my_jni.h
view plaincopy to clipboardprint?
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_easepal_geolo_CActivityMain */
#ifndef _Included_com_easepal_geolo_CActivityMain
#define _Included_com_easepal_geolo_CActivityMain
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_easepal_geolo_CActivityMain
* Method: stringFromJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /*Header for class com_easepal_geolo_CActivityMain */ #ifndef_Included_com_easepal_geolo_CActivityMain #define_Included_com_easepal_geolo_CActivityMain #ifdef __cplusplus extern"C" { #endif /* * Class: com_easepal_geolo_CActivityMain * Method:stringFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALLJava_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv *, jobject); #ifdef__cplusplus } #endif #endif
4. CActivityMain.java
view plaincopy to clipboardprint?
package com.easepal.geolo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class CActivityMain extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText( stringFromJNI("hello") );
setContentView(tv);
}
static {
System.loadLibrary("native");
}
public native String stringFromJNI(String str);
}
package com.easepal.geolo; import android.app.Activity; import android.os.Bundle;import android.widget.TextView; public class CActivityMain extends Activity {/** Called when the activity is first created. */ @Override public voidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);TextView tv = new TextView(this); tv.setText( stringFromJNI("hello")); setContentView(tv); } static { System.loadLibrary("native"); }public native String stringFromJNI(String str); }
5. CForCall.java
view plaincopy to clipboardprint?
package com.easepal.geolo;
public class CForCall{
public CForCall(){};
//public ~CForCall(){};
public String GetJavaString(){
String str;
str = "123456";
return str;
}
}
package com.easepal.geolo; public class CForCall{ public CForCall(){}; //public~CForCall(){}; public String GetJavaString(){ String str; str ="123456"; return str; } }
C/C++调用Java类或方法
其实就是JNI技术,通过JNI技术可以使C/C++与Java之间互相调用。
Java调用C/C++方法很简单,在java源文件中将方法声明中使用native关键字,在c/c++中实现即可。
对于C/C++调用Java相对来说有点麻烦。不过思路很简单。
1) 找到Java中的类
jclass javaCls;
javaCls =env->FindClass("com/xxx /xxx");
2) 创建该类的对象(如果是静态方法,则可以跳过此步)
jobject obj;
jmethodID mid;
mid =env->GetMethodID(javaCls, "<init>", "()V");
if (mid != 0)
obj= env->NewObject(javaCls, mid);
这里需要注意的是GetMethodID里面的第二个参数<init>,其实是构造函数的名字,这个是确定的。“()V”是一个名字标识符,可以通过javap –s java_class_name来获取该标识符。
3) 获取要调用的java方法的句柄
jmethodID useID =env->GetMethodID(javaCls, "setTest", "(I)V");
4) 调用该方法
env->CallxxxMethod(obj,useID);
CallxxxMethod这个有多种函数原型,要根据实际情况选择不同的调用,具体可以参看jni.h文件。
源码面前,了无秘密。附件是从codeproject上下载的,代码写得简单明了,我不多说。
/Files/kongque/src_CJNIJava.zip
posted on 2010-11-2416:32 孔雀 阅读(1961) 评论(3) 编辑 收藏 引用 所属分类: Android
评论
# re: C/C++调用Java类或方法 2010-11-25 09:34 Skill
这个C++调用Java听起来蛮独特的,实用么,应用到哪些方面?多谢指点
回复 更多评论
# re: C/C++调用Java类或方法 2010-11-25 09:40 孔雀
@Skill
如果你有java调用c/c++的需求,那么c/c++调用java的需求也就相应的会出现。相当于是回调java的类或方法。
回复 更多评论
# re: C/C++调用Java类或方法 2010-11-25 10:04 Skill
还有,楼主冒昧问一下,为什么我创建的JVM会失败,直接return到结尾,找不到JVM.dll,我是把JDK中的client中的DLL导入到工程Debug下的,这样会创建失败不知为什么?请指教。
----------------------------------
参考2:
android NDK c调用java代码
上一篇 / 下一篇 2013-02-22 12:11:57 / 个人分类:android开发
在网上查看了有关c调用java的文章,其中着重看了两篇,地址分别是
http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html
http://www.2cto.com/kf/201301/184976.html
第一篇比较详细,第二篇主要讲解了步骤,然后自己去实现自己的方法,这里主要记录使用过程中需要注意的问题
问题一:
c调用java使用的是反射机制,所以在文章中定义的jclass,jmethodID一定要是你原类名,原方法名
问题二:
在映射方法时第四个参数是如何得到的,通过javap -s -p 包名.类名
如果这个类没有涉及其它的类可以使用javac来编译成.class文件,通常我们开发都是使用eclipse开发的,刷新一下工程就会编译里面的java文件生成.class文件,那生成的class文件在哪里,右键项目->属性->java build path->Source底下有一个Default output folder下面有输出的路径,一般默认时项目下的bin/classes目录,然后我们到bin/classes目录下面找到类.class,然后javap -classpath 全路径(到包名) -p -s 包名.类名,在终端就会提示每一个变量和方法对应的
引用自:http://www.51testing.com/html/88/377588-837701.html
---------------------------------------
参考3:
[转载] 基本JNI调用技术(c/c++与java互调) [复制链接]
在C/C++中调用Java的方法一般分为五个步骤:初始化虚拟机、获取类、创建类对象、调用方法和退出虚拟机。
1. 初始化虚拟机
- JNIEnv *env;
- JavaVM *jvm;
- JavaVMInitArgs vm_args;
- JavaVMOption options[3];
- int res;
- //设置参数
- options[0].optionString = "-Djava.compiler=NONE";
- //classpath有多个时,UNIX下以“:”分割。
- options[1].optionString = "-Djava.class.path=.";
- options[2].optionString = "-verbose:jni";
-
- vm_args.version = JNI_VERSION_1_4;
- vm_args.nOptions = 3;
- vm_args.options = options;
- vm_args.ignoreUnrecognized = JNI_TRUE;
- res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
- if (res >= 0)
- {
- //创建虚拟机成功
- }
- int result=0;
- result=jvm->AttachCurrentThread( reinterpret_cast<void**>( &env ), 0 );
- if(result>=0)
- {
- //获取运行环境成功
- }
当线程退出时,需要释放本线程使用的运行环境。
- jvm->DetachCurrentThread();
2 获取类
在进行方法调用之前,需要先获取相应的类,类名称必须包括包名,其中的“.”用“/”代替。
- jclass JavaClass;
- JavaClass = env->FindClass("com/test/TestInterface");
- if(JavaClass != 0)
- {
- //获取成功
- }
3 创建类对象
如果需要调用的方法静态方法,则可以跳过本步骤。反之,则需要构造该对象。构造对象是通过调用类的构造函数来实现的,构咱函数的方法声明为<init>, GetMethodID方法的参数在下一步骤详细说明。
- jobject obj;
- jmethodID ctor;
- ctor = env->GetMethodID(JavaClass,"<init>","()V");
- if(ctor != 0)//获取方法成功
- {
- obj = env->NewObject(JavaClass, ctor);
- }
4 调用方法
调用一个方法需要两个步骤:获取方法句柄和调用方法。
- jmethodID methodID = env->GetMethodID( JavaClass, "setTest","(I)V");
- if(methodID!=0)//获取方法成功
- {
- env->CallVoidMethod( obj, methodID,12);
- }
GetStaticMethodID是用来获取静态方法的定义,GetMethodID则是获取非静态的方法定义。他们传入参数的参数依次为:类定义、方法名称和方法的定义,方法的定义可以用jdk中带的javap工具反编译class文件获取,其格式如下:
- public void setTest(int inTest);
- Signature: (I)V
Signature后面的内容就是方法的定义。
CallVoidMethod是对获取的方法进行调用,JNI接口中提供了一系列的同类方法,包括静态方法的调用函数(如:CallStaticXXXMethod)和非静态的方法(如:CallXXXMethod),其中XXX表示的不同方法返回类型,包括int、object等等。
5 退出虚拟机
退出虚拟机调用方法如下:
- jvm->DestroyJavaVM();
在JNI接口定义中,只有最后一个线程退出时,该方法才会返回,但是我只用一个线程,调用该方法也无法返回。故此建议系统退出时执行该方法,或者整个程序退出时,让虚拟机自己释放。
[注意]:
l 在处理中文字符串时,需要注意Java的char是双字节的,采用Unicode编码,在和C++中的char转换时,需要用到系统API:WideCharToMultiByte和MultiByteToWideChar。
l 注意对运行环境中对象引用时的释放,以免引起内存泄漏。
- jstring str;
- wchar_t *w_buffer =(wchar_t *)env->GetStringChars(str,0);
- env->ReleaseStringChars(str,(const unsigned short *)w_buffer);
6 处理异常
C/C++中调用Java时,一定要捕获并处理Java方法抛出的异常信息,否则可能导致C/C++进程的核心转储(Core Dump)。
异常应在每个方法调用后检查:
- msg = (jstring)env->CallObjectMethod(obj, mid);
- if (env->ExceptionOccurred())
- {
- env->ExceptionDescribe();
- env->ExceptionClear();
- return 0;
- }
二.Java调用C/C++
Java调用C/C++时,遵循几个步骤:
1、 用Java native关键字声明方法为本地方法(非Java语言实现)。
2、 编译该声明类,得到XXX.class文件。
3、 用“javah –jni XXX”命令从该class文件生成C语言头文件(XXX.h)。
4、 采用C语言实现该头文件声明的方法,将实现类编译成库文件(libXXX.so)。
5、 在Java程序中使用System.loadLibrary(XXX)加载该库文件(需要设置-Djava.library.path环境变量指向该库文件存放路径)。
6、 即可象调用Java方法一样,调用native方式声明的本地方法。
来自:http://dev.firnow.com/course/3_p ... 2008520/117073.html
---------------------------------------
参考4:
Android将允许纯C/C++开发应用
---------------------------------------
参考5:
Android-NDK开发之第四个例子--用C/C++调用Java
http://blog.csdn.net/GEOLO/archive/2011/01/28/6167542.aspx
2. geolo.cpp先用FindClass方法找到java类,有点类似java的反射用LoadClass再用CallObjectMethod方法调用Java类的函数。
3. my_jni.h 4. CActivityMain.java
- 5. CForCall.java
- Android JNI有关Java类命名方式(Ljava/lang/String;I)V 其中本句I = Integer
B = Byte
S = Short
C = Char
LXXX; = L加上类名3. 在JNI下面,我们常用的命名方式:static JavaVM *g_VM; //全局环境指针static jclass jNativesClass;(*env)->GetJavaVM(env, &g_VM); //获取env环境指针,这样以后用g_VM就可以了。4. jobjectArray jargv // java数组int getArrayLen(JNIEnv * env, jobjectArray jarray): //获取一个Java数组长度,返回为jsize类型jstring jele = (jstring)(*env)->GetObjectArrayElement(env, jargv, n); //从将Java数组元素n转为本地的jstring
const char *word = (*env)->GetStringUTFChars(env, jele, 0); //将java的utf字符转为c下面的char*5. 记住释放内存,这不是java(*env)->ReleaseStringUTFChars(env, jele, word);6. 有关Java类命名方式(Ljava/lang/String;I)V 其中本句I = Integer不好意思,加入些广告:android高级QQ裙:122699113,盛情邀请有一年左右开发经验的朋友加入。希望有高手可以共同研讨android技术。无论是底层还是游戏开发即可。 感谢每个飘过的朋友捧场。。。。
B = Byte
S = Short
C = Char
LXXX; = L加上类名
引用自:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=61684
------------------------------------
参考6:
android ndk c代码调用java的代码
作者:xlcu发布于 07月19日访问(52)评论(1)
from eoe.cn这里简单说一下ndk中c调用java的方法
至于ndk的环境搭建这里就不说了,有空会贴上来
java调c的感觉相对比较简单,以后有空一并贴上来,这里说下 c去回调java的代码了
首先创建工程就不说了,我们这里展开一个经典例子 helloworld 哈哈哈
第一步,在android工程中 建一个类,里面放个方法,syso一个helloworld。同时建议建立一个activity,这样可以放一个按钮,点击的时候可以看到效果
这里稍微展开下 1:写一个java方法
public void helloFromJava(){
System.out.println("helloFromJava");
}
2:写对应的native方法
static{
System.loadLibrary("Hello");
}
public native void callback1();
3:实现一下调用,放在按钮中去调用,就不说啦
4:这里需要用javah实现一下C头文件的生成,当然也可以不这么做,另外的方法我就不展开了
第二部 在ndk中建立C文件啦
include
include "com_itheima15_ndk4_DataProvider.h" //这个头文件由 jdk 中的javah生成,相信来看这个的,就不需要介绍javah怎么用了哦
//日志模块,习惯性的放一个日志模块,方便去调试
include
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)
JNIEXPORT void JNICALL Java_com_xuchulong_ndk4_DataProvider_callback1
(JNIEnv * env, jobject obj){
//C调用java空方法
/*
* 1、 找到该方法存在哪个类中(找到存在该方法的类)
* 2、在该类中找到该方法
* 3、执行该方法
* /
char classname = "com/xuchulong/ndk4/DataProvider";//这个是我的类名,根据自己情况放,我的helloworld就放在这个里面的
//第一步 找到该类
// jclass (FindClass)(JNIEnv, const char*);
jclass clazz = (*env)->FindClass(env, classname);
//第2步 在该类中找到该方法
// jmethodID (GetMethodID)(JNIEnv, jclass, const char*, const char*);
// jclass 在那个类中查找
// const char* 查找的方法名称
// const char* 方法的签名 jdk javap -s 得到方法的签名
使用方法: javap -s 包名.类名
jmethodID method = (*env)->GetMethodID(env, clazz, "helloFromJava", "()V");
//执行该方法
//void (CallVoidMethod)(JNIEnv, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, method);
}
好了C代码部分完成了 ndk-build一下哦,呵呵
声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息
原文作者: xlcu
原文地址: http://my.eoe.cn/1137028/archive/5742.html
---------------------------------------------
参考7:
Android NDK学习之c/c++调用Java本地实例方法(二)
Android NDK学习之c/c++调用Java本地实例方法,调用本地静态方法下一节!
1,新建工程NdKActivitySample2,编写NdKActivitySample2.java
public class NdKActivitySample2 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
callNativeMethod();
}
});
}
public native void callNativeMethod();
static{
System.loadLibrary("testndk");
}
//c/c++中调用该方法
public void NativeMethod(){
Toast.makeText(this, "调用本地方法成功!", Toast.LENGTH_SHORT).show();
}
}
2,dos下生成本地头文件,cd进入工程目录
mkdir jni
bash
javah -classpath bin -d jni com.test.NdKActivitySample2 //jni目录下生成本地.h头文件
3,编写本地com_test.c文件
#include "com_test_NdKActivitySample2.h"
JNIEXPORT void JNICALL Java_com_test_NdKActivitySample2_callNativeMethod
(JNIEnv *env, jobject obj)
{
jclass cls;
jmethodID mid;
cls = (*env)->GetObjectClass(env,obj);
mid = (*env)->GetMethodID(env,cls,"NativeMethod","()V");
(*env)->CallVoidMethod(env,obj,mid);
}
4,编写Android.mk文件
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=testndk
LOCAL_SRC_FILES :=com_test.c
include $(BUILD_SHARED_LIBRARY)
5,执行程序,即可!
源码
有问题,qq:465144122!
------------------------------
参考7:
Android NDK开发之Jni调用Java对象
- 博客分类:
- Android那些事儿
本地代码中使用Java对象
通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。
构造一个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);
那其他情况呢?请查看下表:
类型符号booleanZbyteBcharCshortSintIlongLfloatFdoubleDvoidVobject对象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;
- }
引用自:http://zhiweiofli.iteye.com/blog/1830321
--------------------------------------
参考8:
基于 Android NDK 的学习之旅----- C调用Java
许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现。
下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态方法。
1、主要流程
1、 新建一个测试类TestProvider.java
a) 该类提供了2个方法
b) 一个静态的方法,一个非静态的方法
2、 JNI中新建Provider.c
a) 该文件中需要把Java中的类TestProvider映射到C中
b) 把TestProvider的两个方法映射到C中
c) 新建TestProvider 对象
d) 调用两个方法
3、 Android 上层 调用 JNI层
4、 JNI层调用C层
5、 C 层调用 Java 方法
2、设计实现
1、界面设计如下:
老样子,很搓,不过实用,嘿嘿
代码不在这贴出了,有需要的兄弟直接到文章结束部分下载。
2、 关键代码说明
C中定义映射的类、方法、对象
jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;
C 中映射 类
TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
C中新建对象
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider,"<init>", "()V");
TestProvider mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);
C 中映射方法
静态:
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
非静态:
sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");
C 中调用 Java的 方法
静态:
(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
非静态:
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
注意 GetXXXMethodID 和 CallXXXMethod 。
第一个XXX 表示的是映射方法的类型,如: 静态 跟非静态
第二个 XXX 表示 调用方法的返回值 ,如:Void,Object,等等。(调用静态方法的时候Call后面要加Static)
详细 映射方法 和 调用方法 请参考 JNI 文档 ,这个很重要 !
3、 Java 上层 关键代码
TestProvider.Java 的两个方法
package
com.duicky;
/**
*
*
* @author luxiaofeng <454162034@qq.com>
*
*/
public
class
TestProvider {
public
static
String getTime() {
LogUtils.printWithSystemOut(
"Call From C Java Static Method"
);
LogUtils.toastMessage(MainActivity.mContext,
"Call From C Java Static Method"
);
return
String.valueOf(System.currentTimeMillis());
}
public
void
sayHello(String msg) {
LogUtils.printWithSystemOut(
"Call From C Java Not Static Method :"
+ msg);
LogUtils.toastMessage(MainActivity.mContext,
"Call From C Java Not Static Method :"
+ msg);
}
}
4、 Android.mk 文件 关键代码
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_MODULE := NDK_04
LOCAL_SRC_FILES := \
CToJava.c \
Provider.c
include $(BUILD_SHARED_LIBRARY)
老样子,不说了,你懂的。 如果不懂,嘎嘎,那就请点击Android.mk 文件 简介
5、 JNI文件夹下文件
Provider.h
#include <string.h>
#include <jni.h>
void
GetTime() ;
void
SayHello();
Provider.c
#include "Provider.h"
#include <android/log.h>
extern
JNIEnv* jniEnv;
jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;
int
GetProviderInstance(jclass obj_class);
/**
* 初始化 类、对象、方法
*/
int
InitProvider() {
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 1"
);
if
(jniEnv == NULL) {
return
0;
}
if
(TestProvider == NULL) {
TestProvider = (*jniEnv)->FindClass(jniEnv,
"com/duicky/TestProvider"
);
if
(TestProvider == NULL){
return
-1;
}
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 2 ok"
);
}
if
(mTestProvider == NULL) {
if
(GetProviderInstance(TestProvider) != 1) {
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
return
-1;
}
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 3 ok"
);
}
if
(getTime == NULL) {
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider,
"getTime"
,
"()Ljava/lang/String;"
);
if
(getTime == NULL) {
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
(*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
return
-2;
}
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 4 ok"
);
}
if
(sayHello == NULL) {
sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider,
"sayHello"
,
"(Ljava/lang/String;)V"
);
if
(sayHello == NULL) {
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
(*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
(*jniEnv)->DeleteLocalRef(jniEnv, getTime);
return
-3;
}
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 5 ok"
);
}
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProvider Begin 6"
);
return
1;
}
int
GetProviderInstance(jclass obj_class) {
if
(obj_class == NULL) {
return
0;
}
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class,
"<init>"
,
"()V"
);
if
(construction_id == 0) {
return
-1;
}
mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class,
construction_id);
if
(mTestProvider == NULL) {
return
-2;
}
return
1;
}
/**
* 获取时间 ---- 调用 Java 方法
*/
void
GetTime() {
if
(TestProvider == NULL || getTime == NULL) {
int
result = InitProvider();
if
(result != 1) {
return
;
}
}
jstring jstr = NULL;
char
* cstr = NULL;
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"GetTime Begin"
);
jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
cstr = (
char
*) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0);
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"Success Get Time from Java , Value = %s"
,cstr );
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"GetTime End"
);
(*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr);
(*jniEnv)->DeleteLocalRef(jniEnv, jstr);
}
/**
* SayHello ---- 调用 Java 方法
*/
void
SayHello() {
if
(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) {
int
result = InitProvider() ;
if
(result != 1) {
return
;
}
}
jstring jstrMSG = NULL;
jstrMSG =(*jniEnv)->NewStringUTF(jniEnv,
"Hi,I'm From C"
);
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"SayHello Begin"
);
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"SayHello End"
);
(*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG);
}
CToJava.c
#include <string.h>
#include <android/log.h>
#include <jni.h>
#include "Provider.h"
JNIEnv* jniEnv;
/**
* Java 中 声明的native getTime 方法的实现
*/
void
Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz)
{
if
(jniEnv == NULL) {
jniEnv = env;
}
GetTime();
}
/**
* Java 中 声明的native sayHello 方法的实现
*/
void
Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz)
{
if
(jniEnv == NULL) {
jniEnv = env;
}
SayHello();
}
3、运行效果
1、点击 “C调用java静态方法”按钮
C成功调用了Java中的getTime 方法,通过C方法打印出上层调用得到的时间,并且上层成功吐司出调用信息出来。
2、点击 “C调用java非静态方法”按钮
C成功调用了sayHello 方法, 并成功接收到 C 传递的参数,和 吐司出相对应的信息
4、C调用Java注意点
a) C 映射java 方法时 对应的签名
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
故事情节还没发展这么快,下一章才会专门介绍下这个签名的使用
b)映射方法的时候需要区别静态和非静态GetStaticMethodID,GetMethodID
c)调用的时候也需要区分CallStaticObjectMethod,CallVoidMethod 而且还需要区分返回值类型
有不理解的兄弟请留言,个人技术有限,有讲错的地方请大牛们指出,讲的不够全面的请多多包涵,谢谢,
点击下载源码 C调用Java例子
本文出自 duicky 博客 , 转载请注明出处 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html
引用自:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html
- 成功实现C/C++调用Java (Android NDK 开发)--参考1
- android NDK--C 调用java
- Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用
- Android NDK开发 Java与C互相调用实例详解
- Android NDK开发----- Java与C互相调用实例详解
- Android NDK开发----- Java与C互相调用实例详解
- Android NDK开发之c调用java方法
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- Android 基于NDK的JNI开发 C调用java和java调用C的进阶教程
- NDK开发java调用c(三)
- Android NDK 调用C
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解
- Android NDK开发(1)----- Java与C互相调用实例详解 .
- Object类总结
- 一个基于WF的业务流程平台
- 图片滚轮插件-SCROLLER
- 分布式系统监视 zabbix
- 查找N个数中第K大的数
- 成功实现C/C++调用Java (Android NDK 开发)--参考1
- eclipse设置
- 服务器同步工具 sersync
- 界面通告对话框-BACKBONE.NOTIFIER
- 百度2014移动研发笔试题目——1013清华版
- 单机TCP最大连接数简析
- Windows系统下nodejs安装及配置
- Google工程师多图详解Android系统架构
- MyEclipse svn必备技能之常用菜单