JAVA和C/C++之间的相互调用。
在一些Android应用的开发中,需要通过JNI和 Android NDK工具实现JAVA和C/C++之间的相互调用。
Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI是本地编程接口,它使得在 Java 虚拟机 (VM)内部运行的 Java代码能够与用其它编程语言(如C、C++和汇编语言)编写的应用程序和库进行交互操作。
由于Android的应用层的类都是以Java写的,这些Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Machine)来执行。在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。
在实际应用中这两者之间的调用关系可以归纳为以下四种方式:
1. 在应用的JAVA代码中调用NDK中C/C++实现的函数。
2. 在NDK开发中的C/C++代码调用应用中JAVA类的静态函数。
3. 在NDK开发中的C/C++代码调用应用中JAVA类当前传入NDK中的实例的函数。
4. 在NDK开发中的C/C++代码调用应用中JAVA类新建实例的函数。
下面我们就怎样在Eclipse中实现JNI编码和四种调用方式加以阐述。
一、在Eclipse中建立一个包含JNI开发的工程。
在这里我们不直接导入NDK中的hello-jni来说明JNI的使用方法。而是新建立一个工程,来说明怎样建立一个包含JNI的工程。
第一步:建立一个Andriod工程JniDemo,在该工程的根目录下建立一个叫jni的目录,在jni目录下建立一个叫Android.mk的文件,(当然你也可以从其他地方,比如ndk样例代码hello-jni中将里面的Android.mk复制过来修改)。 Android.mk里面的内容如下所示
LOCAL_PATH :=$(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE := demo-jni
LOCAL_SRC_FILES := demo-jni.c
include$(BUILD_SHARED_LIBRARY)
关于这几句话的含义,在这里不再赘述。网上搜下,就可以很明白。
然后在jni目录下生成demo-jni.c文件。实现的接口的内容。
现在选中工程中的jni目录,点击鼠标右键,选Refresh,jni目录中的文件就显示在工程的jni目录下了。
第二步:设置jni的编译环境。选中工程中的根目录JniDemo,点击鼠标右键,选Properties。弹出对话框,选中列表中的Builders。如图一所示:
图一:JniDemo特性设置对话框
点击对话框右端的new按钮,弹出“Choose configuration type”对话框,如图二,选择Program,点击对话框下面的OK按钮。
图二:选择配置类型
现在我们打开了”Edit Configuration”对话框,在Name对应的文本框中输入名字JniBuilder(当然也可是你喜欢的其他名字).在Main选项下,在Location中输入cygwin系统中bash.exe的绝对路径。我这里是c:\cygwin\bin\bash.exe(c:\cygwin\为我的系统中cygwin的安装目录,这里要根据你的电脑中cygwin的安装目录来确定),在Working Directory中输入c:\cygwin\bin\.在Arguments中输入--login -c "cd /cygdrive/d/study/JniDemo && /cygdrive/d/android-ndk-r6b/ndk-build"。这里/cygdrive/d/study/JniDemo为工程根目录, /cygdrive/d/android-ndk-r6b为NDK的安装目录。这两个目录参数根据你的工程目录和ndk的安装目录而定。注意的是驱动器要采用cygwin的方式。(比如:Windows系统下的D:对应/cygdrive/d,其余类推)。设置结果如图三所示,然后点击 OK按钮即可。
图三:编辑JNI配置参数
二、演示四种调用方式
演示界面如图四所示,四个按钮分别测试四种调用方式。
图四:演示界面图
分别点击按钮Test1, Test2, Tes3, Test四的测试结果如图五、六、七、八所示。
图五:点击Test1的测试结果
图六:点击Test2的测试结果
图七:点击Test3的测试结果
图八:点击Test4的测试结果
Test1演示在应用中调用NDK中C/C++实现的函数。JAVA代码和C代码分别为:
JAVA 代码:
- Button btn01 = (Button)findViewById(R.id.Button01);
- btn01.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- TextView tv = (TextView)findViewById(R.id.tv01);
- tv.setText(stringFromJNI());
- showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());
- }
- });
C代码:
- Jstring Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )
- {
- return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");
- }
l Test2 静态调用。JAVA代码和C代码分别为:
JAVA 代码:
- // 测试C/C++中对JAVA函数的静态回调
- Button btn02 = (Button)findViewById(R.id.Button02);
- btn02.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2","test static callback Message");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI static callback successed");
- }
- else
- {
- tv.setText("test JNI static callback fialed");
- }
- }
- });
C代码:
- Jint Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env,
- jobject thiz,jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
- // jclass cls = (*env)->GetObjectClass(env, thiz);
- if(cls != NULL)
- {
- jmethodID id = (*env)->GetStaticMethodID(env, cls,"staticShowMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(id != NULL)
- {
- return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);
- }
- }
- return 1;
- }
l Test3 当前实例调用:JAVA代码和C代码分别为:
JAVA 代码:
- Button btn03 = (Button)findViewById(R.id.Button03);
- btn03.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- strTest = " [message has changed now]";
- int ret = jniShowMessage(JniDemoActivity.this,"JNI test3","test callback in current instance");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI callback successed");
- }
- else
- {
- tv.setText("test JNI callback fialed");
- }
- }
- });
C代码:
- Jint Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,
- jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->GetObjectClass(env, thiz);
- if(cls != NULL)
- {
- jstring str;
- jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");
- if(strTest_id != NULL)
- {
- str = (*env)->CallObjectMethod(env, thiz, strTest_id);
- }
- jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(showMessage_id != NULL)
- {
- return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,
- strTitle, combine_jstring(env, strMessage, str));
- }
- }
- return 1;
- }
l Test4新建实例调用:JAVA代码和C代码分别为:
JAVA 代码:
- Button btn04 = (Button)findViewById(R.id.Button04);
- btn04.setOnClickListener(newButton.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- strTest = " [message has changed now]";
- int ret = jniInstanceShowMessage(JniDemoActivity.this,
- JNI test4","test callback in new instance");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI new instance successed");
- }
- else
- {
- tv.setText("test JNI new instance fialed");
- }
- }
- });
C代码:
- jint Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,
- jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
- if(cls != NULL)
- {
- // get instance
- jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>", "()V");
- if(constuctor_id != NULL)
- {
- jobject obj = (*env)->NewObject(env, cls, constuctor_id);
- if(obj != NULL)
- {
- jstring str;
- jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");
- if(strTest_id != NULL)
- {
- str = (*env)->CallObjectMethod(env, obj, strTest_id);
- }
- jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(showMessage_id != NULL)
- {
- return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,strTitle, combine_jstring(env, strMessage, str));
- }
- }
- }
- }
- return 1;
- }
Test1 和Test2都是常规的调用,在这里不做解释了。现在我们看看Test3和Test4的区别,在Test3中,strTest = " [message has changed now]" 在相应的代码中都做了赋值。但是在Test4中并没有改变,还是初始值。这是因为Test创建了一个新实例,和应用的JAVA代码中所赋值的实例并不是同一个。因此才出现了不同的结果。
附完整的JAVA和C代码
JAVAD代码: JniDemoActivity.java
- package study.jnidemo;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.os.Bundle;
- import android.widget.Button;
- import android.view.View;
- import android.widget.TextView;
- import android.content.Context;
- import android.content.DialogInterface;
- publicclass JniDemoActivityextends Activity {
- public StringstrTest =" [initial message]";
- /** Called when the activity is first created. */
- @Override
- publicvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- findAndModifyButton();
- }
- public String getTestString()
- {
- returnstrTest;
- }
- // 测试JAVA的NDK调用
- publicnative String stringFromJNI();
- // 测试C/C++中对JAVA函数的静态回调
- publicnativestaticint jniStaticShowMessage(Context ctx, String strTitle, String strMessage);
- // 测试实例中C/C++中对JAVA类的函数的调用
- publicnativeint jniShowMessage(Context ctx, String strTitle, String strMessage);
- // 测试创建新实例C/C++对JAVA类的函数的调用
- publicnativeint jniInstanceShowMessage(Context ctx, String strTitle, String strMessage);
- static {
- System.loadLibrary("demo-jni");
- }
- staticint staticShowMessage(Context ctx, String strTitle, String strMessage)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
- builder.setTitle(strTitle);
- builder.setMessage(strMessage);
- builder.setPositiveButton("确定",
- new DialogInterface.OnClickListener(){
- public void onClick(DialogInterface dialog,int whichButton){
- }
- });
- builder.show();
- return 0;
- }
- publicint showMessage(Context ctx, String strTitle, String strMessage)
- {
- returnstaticShowMessage(ctx, strTitle, strMessage);
- }
- privatevoid findAndModifyButton()
- {
- // 测试JAVA的NDK调用
- Button btn01 = (Button)findViewById(R.id.Button01);
- btn01.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- TextView tv = (TextView)findViewById(R.id.tv01);
- tv.setText(stringFromJNI());
- showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());
- }
- });
- // 测试C/C++中对JAVA函数的静态回调
- Button btn02 = (Button)findViewById(R.id.Button02);
- btn02.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2", "test static callback Message");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI static callback successed");
- }
- else
- {
- tv.setText("test JNI static callback fialed");
- }
- }
- });
- // 测试实例中C/C++中对JAVA类的函数的调用
- Button btn03 = (Button)findViewById(R.id.Button03);
- btn03.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- strTest = " [message has changed now]";
- int ret = jniShowMessage(JniDemoActivity.this,"JNI test3", "test callback in current instance");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI callback successed");
- }
- else
- {
- tv.setText("test JNI callback fialed");
- }
- }
- });
- // 测试创建新实例C/C++对JAVA类的函数的调用
- Button btn04 = (Button)findViewById(R.id.Button04);
- btn04.setOnClickListener(new Button.OnClickListener()
- {
- publicvoid onClick(View v)
- {
- strTest = " [message has changed now]";
- int ret = jniInstanceShowMessage(JniDemoActivity.this,"JNI test4", "test callback in new instance");
- TextView tv = (TextView)findViewById(R.id.tv01);
- if(ret == 0)
- {
- tv.setText("test JNI new instance successed");
- }
- else
- {
- tv.setText("test JNI new instance fialed");
- }
- }
- });
- }
- }
C代码 demo-jni.cpp
- #include<string.h>
- #include<jni.h>
- // 加载此动态库时系统自动首先加载
- jint JNI_OnLoad(JavaVM* vm, void *reserved)
- {
- JNIEnv *env;
- if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)
- {
- return -1;
- }
- return JNI_VERSION_1_4;
- }
- jstring
- Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )
- {
- return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");
- }
- jstring
- combine_jstring(JNIEnv* env, jstring str1, jstring str2)
- {
- jboolean b_ret;
- constchar *s1 = (*env)->GetStringUTFChars(env, str1, &b_ret);
- constchar *s2 = (*env)->GetStringUTFChars(env, str2, &b_ret);
- int n1 = strlen(s1);
- int n2 = strlen(s2);
- char *new_str = (char *)malloc(n1+n2+1);
- memset(new_str, 0, n1+n2+1);
- strcat(new_str, s1);
- strcat(new_str, s2);
- jstring ret_str = (*env)->NewStringUTF(env,(constchar *)new_str);
- free(new_str);
- return ret_str;
- }
- jint
- Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env, jobject thiz,
- jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
- // jclass cls = (*env)->GetObjectClass(env, thiz);
- if(cls != NULL)
- {
- jmethodID id = (*env)->GetStaticMethodID(env, cls,
- "staticShowMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(id != NULL)
- {
- return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);
- }
- }
- return 1;
- }
- // 在当前已有的JAVA实例中调用
- jint
- Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,
- jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->GetObjectClass(env, thiz);
- if(cls != NULL)
- {
- jstring str;
- jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString",
- "()Ljava/lang/String;");
- if(strTest_id != NULL)
- {
- str = (*env)->CallObjectMethod(env, thiz, strTest_id);
- }
- jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(showMessage_id != NULL)
- {
- return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,
- strTitle, combine_jstring(env, strMessage, str));
- }
- }
- return 1;
- }
- // 在新建JAVA实例中调用
- jint
- Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,
- jobject ctx, jstring strTitle, jstring strMessage)
- {
- jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");
- if(cls != NULL)
- {
- // get instance
- jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>", "()V");
- if(constuctor_id != NULL)
- {
- jobject obj = (*env)->NewObject(env, cls, constuctor_id);
- if(obj != NULL)
- {
- jstring str;
- jmethodID strTest_id = (*env)->GetMethodID(env, cls,"getTestString",
- "()Ljava/lang/String;");
- if(strTest_id != NULL)
- {
- str = (*env)->CallObjectMethod(env, obj, strTest_id);
- }
- jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");
- if(showMessage_id != NULL)
- {
- return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,
- strTitle, combine_jstring(env, strMessage, str));
- }
- }
- }
- }
- return 1;
- }
源代码下载地址:http://download.csdn.net/detail/seniorwizard/4394466
JAVA和C/C++之间的相互调用。的更多相关文章
- C 程序与 C++ 程序之间的相互调用
因为 C 编译器编译函数时不带参数的类型信息,只包含函数的符号名字.如 void foo( int x ) , C 编译器会将此函数编译成类似 _foo 的符号,C 链接器只要找到了调用函数的符号,就 ...
- C#与Javascript变量、函数之间的相互调用
原文地址:http://blog.csdn.net/wonsoft/article/details/2595743 C#与Javascript变量.函数之间的相互调用 一.javascript调用C ...
- Java与.NET 的Web Services相互调用
一:简介 本文介绍了Java与.NET开发的Web Services相互调用的技术.本文包括两个部分,第一部分介绍了如何用.NET做客户端调用Java写的Web Services,第二部分介绍了如何用 ...
- 关于cocos2d-x 和安卓之间的相互调用
近期在研究cocos2d游戏移植安卓须要调用非常多方法.所以在研究之中写下它们之间相互调用 首先,cocos2d调用安卓 在一个.h文件里加入头文件 #include <jni.h> #i ...
- uLua学习笔记(三):Unity3D和Lua之间的相互调用
这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方 ...
- Iframe父页面与子页面之间的相互调用
iframe元素就是文档中的文档. window对象: 浏览器会在其打开一个HTML文档时创建一个对应的window对象.但是,如果一个文档定义了一个或者多个框架(即:包含一个或者多个frame或者i ...
- 两个java工程之间的相互调用方法
如果你有两个java项目的话,如何向他们之间进行信息的通信前提:必须知道要通信的java项目(接收请求方)的服务器的IP地址和访问路径.其实两个java项目之间的通信还是使用HTTP的请求.主要有两种 ...
- 032 搭建搜索微服务01----向ElasticSearch中导入数据--通过Feign实现微服务之间的相互调用
1.创建搜索服务 创建module: Pom文件: <?xml version="1.0" encoding="UTF-8"?> <proje ...
- C和Lua之间的相互调用
前面的话 第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的.这次打算好好了解一下C跟lua是如何交互的 那么如何使用Lua语言? lua ...
随机推荐
- php数组函数序列之array_unshift() 在数组开头插入一个或多个元素
array_unshift() 函数在数组开头插入一个或多个元素.被加上的元素作为一个整体添加,这些元素在数组中的顺序和在参数中的顺序一样 array_unshift()定义和用法 array_uns ...
- hdu2015
http://acm.hdu.edu.cn/showproblem.php?pid=2015 #include<iostream> #include<stdio.h> #inc ...
- 区间dp笔记√
区间DP是一类在区间上进行dp的最优问题,一般是根据问题设出一个表示状态的dp,可以是二维的也可以是三维的,一般情况下为二维. 然后将问题划分成两个子问题,也就是一段区间分成左右两个区间,然后将左右两 ...
- linux上应用程序的执行机制
linux上应用程序的执行机制 执行文件是如何在shell中被"执行"的.本文中尽可能少用一些源码,免得太过于无 聊,主要讲清这个过程,感兴趣的同学可以去查看相应的源码了解更多的信 ...
- Error building Player: Win32Exception: ApplicationName=‘xxxxxxxxxxxxxxxxxx//sdk\tools\zipalign.exe' , CommandLine='4 的解决办法
更新了安卓SDK后,有时候Unity编译失失败,报错类似 Error building Player: Win32Exception: ApplicationName='D:/Program File ...
- Android:文件夹显示红色叹号
有感叹号,说明有的文件损坏或丢失了 解决方法: 右击工程,Build Path..->Configure Build Path...->Java Build Path 可以看到引用的jar ...
- ORA-12571 : TNS : 包写入程序失败
错误原因 解决方案 修改D:/oracle/ora92/network/admin目录下sqlnet.ora,将”NAMES.DEFAULT_DOMAIN =” 这一行用#注释掉,将“SQLNET.A ...
- Centos硬件信息查看命令
[root@yan-001 ~] # uname -a # 查看内核/操作系统/CPU信息的linux系统信息命令 [root@yan-001 ~] # head -n 1 /etc/issue # ...
- Android 类似时间轴的实现
想要实现图片中的的时间轴的效果,设定了三种颜色,但是出来的只有一个黑色,还不是设定好的,而且长度很长的话不能滚动,下面上代码: 布局文件: <LinearLayout xmlns:android ...
- Android ActionBar的Overlay模式如何不遮盖顶部内容的问题
关于actionbar的overlay模式请参考 如何让android的actionbar浮动且透明 一文.这篇文章讲的是如何在这种模式下让actionbar不遮住顶部的内容. 这 一般是这样的场景, ...