Android 中Java 和C/C++的相互调用方法
来源:互联网 发布:苹果软件推广 编辑:程序博客网 时间:2024/04/29 15:59
本文转载自:http://blog.csdn.net/seniorwizard/article/details/7693573 在一些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!");}
Test2 静态调用。JAVA代码和C代码分别为:
JAVA 代码:
Test2 静态调用。JAVA代码和C代码分别为:JAVA 代码:
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;}
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;}
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;} jstringJava_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz ){ return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");}jstringcombine_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;}jintJava_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实例中调用jintJava_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实例中调用jintJava_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
- Android 中Java 和C/C++的相互调用方法
- Android 中Java 和C/C++的相互调用方法
- Android 中Java 和C/C++的相互调用方法
- Android 中Java 和C/C++的相互调用方法
- Android 中Java 和C/C++的相互调用方法
- Android java层和C层的相互调用
- JS和C#方法相互调用
- Android 平台下Java与C/C++的相互调用
- Android NDK环境搭建及JNI开发java和C的相互调用的基本介绍
- Android JNI 在C中调用Java(包括自定义的Java方法和Log)
- Android JNI中C调用Java方法
- Java程序和C程序的相互调用
- 使用thrift做c++,java和python的相互调用
- JAVA和C/C++相互调用
- Android webview中JavaScript与Java方法的相互调用
- asm和c的相互调用
- C 和C++ 之间的相互调用
- C++和C的相互调用
- HTTP协议详解
- Android webView和js交互
- Mybatis入门实例(二)——添加ehcache缓存支持
- 求最近的两点坐标
- intent发送邮件
- Android 中Java 和C/C++的相互调用方法
- 通信原理中星座图详解
- Mybatis入门实例(三)——使用MyBatis Generator生成DAO
- Android小知识——dp转成px和px转成dp
- IOS-UIView转UIImage并保存到本地相册
- CentOS 7安装Mysql
- 纯裸 SPFA 适合初学者作为模板练习
- Lua和C++交互详细总结_3_C++调用Lua
- 优化 WebLogic