android-ndk 数据传递

来源:互联网 发布:单农男装网络旗舰店 编辑:程序博客网 时间:2024/05/18 00:44

首先定义DataProvider

package com.example.testndkpassdata;public class DataProvider {/** * 把两个java中的int传递给c语言, c语言处理完毕后,把相加的结果返回给java * @param x  * @param y * @return */public native int add(int x ,int y);public static native int sub(int x ,int y);public native char add(char x, char y); //String /** * 把java中的string传递给c语言, c语言获取到java中的string之后 ,在string后面添加 一个hello 字符串 * @param s * @return */public native String sayHelloInC(String s);/** * 把java中的一个int数组 传递给c语言,c语言处理完毕这个java数组  * 把int数组中的每一个元素+10 ; * 然后把结果返回给java * @param iNum * @return */public native int[] intMethod(int[] iNum); public native byte[] byteMethod(byte[] iByte);public native DiskInfo getStruct();}
编译生成C/C++头文件 

定义好了Java类之后,接下来就要写本地代码。本地方法符号提供一个满足约定的头文件,使用Java工具Javah可以很容易地创建它而不用手动去创建。你对Java的class文件使用javah命令,就会为你生成一个对应的C/C++头文件。
1、在控制台下进入工作路径,本工程路径为:E:\work\java\workspace\testndkpassdata。
2、运行javah 命令:javah -classpath E:\work\java\workspace\JavaJni com.example.testndkpassdata ChangeMethodFromJni
本文生成的C/C++头文件名为: com_example_testndkpassdata_DataProvider.h
在C/C++中实现本地方法

生成C/C++头文件之后,你就需要写头文件对应的本地方法。注意:所有的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的。第二个参数jclass的意义,要看方法是不是静态的(static)或者实例(Instance)的。前者,jclass代表一个类对象的引用,而后者是被调用的方法所属对象的引用。

返回值和参数类型根据等价约定映射到本地C/C++类型,如表JNI类型映射所示。有些类型,在本地代码中可直接使用,而其他类型只有通过JNI调用操作。


数组:

JNI通过JNIEnv提供的操作Java数组的功能。它提供了两个函数:一个是操作java的简单型数组的,另一个是操作对象类型数组的。

因为速度的原因,简单类型的数组作为指向本地类型的指针暴露给本地代码。因此,它们能作为常规的数组存取。这个指针是指向实际的Java数组或者Java数组的拷贝的指针。另外,数组的布置保证匹配本地类型。

为了存取Java简单类型的数组,你就要要使用GetXXXArrayElements函数(见表B),XXX代表了数组的类型。这个函数把Java数组看成参数,返回一个指向对应的本地类型的数组的指针。


当你对数组的存取完成后,要确保调用相应的ReleaseXXXArrayElements函数,参数是对应Java数组和GetXXXArrayElements返回的指针。如果必要的话,这个释放函数会复制你做的任何变化(这样它们就反射到java数组),然后释放所有相关的资源。

为了使用java对象的数组,你必须使用GetObjectArrayElement函数和SetObjectArrayElement函数,分别去get,set数组的元素。GetArrayLength函数会返回数组的长度。

使用对象

JNI提供的另外一个功能是在本地代码中使用Java对象。通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。

表C列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldIDjmethodID。


如果你有了一个类的实例,它就可以通过方法GetObjectClass得到,或者如果你没有这个类的实例,可以通过FindClass得到。符号是从域的类型或者方法的参数,返回值得到字符串,如表D所示。


头文件
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_testndkpassdata_DataProvider */#ifndef _Included_com_example_testndkpassdata_DataProvider#define _Included_com_example_testndkpassdata_DataProvider#ifdef __cplusplusextern "C" {#endif/* * Class:     com_example_testndkpassdata_DataProvider * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_testndkpassdata_DataProvider_add__II  (JNIEnv *, jobject, jint, jint);/* * Class:     com_example_testndkpassdata_DataProvider * Method:    sub * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_testndkpassdata_DataProvider_sub  (JNIEnv *, jclass, jint, jint);/* * Class:     com_example_testndkpassdata_DataProvider * Method:    add * Signature: (CC)C */JNIEXPORT jchar JNICALL Java_com_example_testndkpassdata_DataProvider_add__CC  (JNIEnv *, jobject, jchar, jchar);/* * Class:     com_example_testndkpassdata_DataProvider * Method:    sayHelloInC * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_testndkpassdata_DataProvider_sayHelloInC  (JNIEnv *, jobject, jstring);/* * Class:     com_example_testndkpassdata_DataProvider * Method:    intMethod * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_example_testndkpassdata_DataProvider_intMethod  (JNIEnv *, jobject, jintArray);/* * Class:     com_example_testndkpassdata_DataProvider * Method:    byteMethod * Signature: ([B)[B */JNIEXPORT jbyteArray JNICALL Java_com_example_testndkpassdata_DataProvider_byteMethod  (JNIEnv *, jobject, jbyteArray);JNIEXPORT jobject JNICALL Java_com_example_testndkpassdata_DataProvider_getStruct  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
bean文件
package com.example.testndkpassdata;public class DiskInfo {  public String name;  public int serial;  public String getName() {    return name;  }  public void setName(String name) {    this.name = name;  }  public int getSerial() {    return serial;  }  public void setSerial(int serial) {    this.serial = serial;  }  }


实现文件
#include<stdio.h>#include<jni.h>#include "com_example_testndkpassdata_DataProvider.h";#include <android/log.h>#include<malloc.h>#define LOG_TAG "System.out.c"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)/** * 返回值 char* 这个代表char数组的首地址 *  Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串 */char* Jstring2CStr(JNIEnv* env, jstring jstr) {char* rtn = NULL;jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //Stringjstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312"jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes","(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid,strencode); // String .getByte("GB2312");jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);if (alen > 0) {rtn = (char*) malloc(alen + 1);         //"\0"memcpy(rtn, ba, alen);rtn[alen] = 0;}(*env)->ReleaseByteArrayElements(env, barr, ba, 0);  //return rtn;}JNIEXPORT jint JNICALL Java_com_example_testndkpassdata_DataProvider_add__II(JNIEnv * env, jobject obj, jint x, jint y) {LOGD("x=%d", x);LOGD("y=%d", y);return x + y;}JNIEXPORT jstring JNICALL Java_com_example_testndkpassdata_DataProvider_sayHelloInC(JNIEnv * env, jobject obj, jstring jstr) {/*//在c语言中 是没有java的String char* cstr = Jstring2CStr(env, jstr); LOGD("cstr=%s",cstr); // c语言中的字符串 都是以'/0' 作为结尾 char arr[7]= {' ','h','e','l','l','o','\0'}; strcat(cstr,arr); LOGD("new cstr=%s",cstr); return (*env)->NewStringUTF(env,cstr);*/const char* szStr = (*env)->GetStringUTFChars(env, jstr, 0);// c语言中的字符串 都是以'/0' 作为结尾char arr[7] = { ' ', 'h', 'e', 'l', 'l', 'o', '\0' };strcat(szStr, arr);(*env)->ReleaseStringUTFChars(env, jstr, szStr);return (*env)->NewStringUTF(env, szStr);}/**env java 虚拟机 结构体c实现的指针 包含的有很多jni方法 *jobject obj 代表的是调用这个c代码的java对象 代表的是DataProider的对象 */JNIEXPORT jintArray JNICALL Java_com_example_testndkpassdata_DataProvider_intMethod(JNIEnv * env, jobject obj, jintArray arr) {//1.知道数组的长度//2.操作这个数组里面的每一个元素int len = (*env)->GetArrayLength(env, arr);LOGD("shuzu len =%d", len);//    jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);jint* intarr = (*env)->GetIntArrayElements(env, arr, NULL);int i = 0; //c99for (; i < len; i++) {//*(intarr+i) += 10;LOGD("intarr[%d]=%d", i, intarr[i]);intarr[i] += 10;}//    void        (*ReleaseIntArrayElements)(JNIEnv*, jintArray,//                        jint*, jint);//(*env)->ReleaseIntArrayElements(env, arr, intarr, NULL); // c语言释放掉 刚才申请的内存空间return arr;}/** * 代表的是调用c代码 的class类 * jclass DataProvider  类 */JNIEXPORT jint JNICALL Java_com_example_testndkpassdata_DataProvider_sub(JNIEnv * env, jclass clazz, jint x, jint y) {LOGD("x=%d", x);LOGD("y=%d", y);return x - y;}//返回一个结构,这里返回一个硬盘信息的简单结构类型JNIEXPORT jobject JNICALL Java_com_example_testndkpassdata_DataProvider_getStruct(JNIEnv *env, jobject obj) {/* 下面为获取到Java中对应的实例类中的变量*///获取Java中的实例类jclass objectClass = (*env)->FindClass(env,"com/example/testndkpassdata/DiskInfo");jmethodID m    = (*env)->GetMethodID(env,objectClass,"<init>","()V");jobject Diskobj=(*env)->NewObject(env,objectClass,m);//获取类中每一个变量的定义//名字jfieldID str = (*env)->GetFieldID(env,objectClass, "name", "Ljava/lang/String;");//序列号jfieldID ival = (*env)->GetFieldID(env,objectClass, "serial", "I");//给每一个实例的变量付值(*env)->SetObjectField(env,Diskobj, str, (*env)->NewStringUTF(env,"my name is D:"));(*env)->SetIntField(env,Diskobj, ival, 10);//(*env)->DeleteLocalRef(env, m);//(*env)->DeleteLocalRef(env, str);//(*env)->DeleteLocalRef(env, ival);//(*env)->DeleteLocalRef(env, objectClass);return Diskobj;}
测试文件
package com.example.testndkpassdata;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener{  static{    System.loadLibrary("Hello");  }  private Button bt1,bt2,bt3,bt4,bt5;  private DataProvider provider;  private DiskInfo diskInfo;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    bt1 = (Button) this.findViewById(R.id.bt1);    bt2 = (Button) this.findViewById(R.id.bt2);    bt3 = (Button) this.findViewById(R.id.bt3);    bt4 = (Button) this.findViewById(R.id.bt4);    bt5=(Button)this.findViewById(R.id.bt5);        bt1.setOnClickListener(this);    bt2.setOnClickListener(this);    bt3.setOnClickListener(this);    bt4.setOnClickListener(this);    bt5.setOnClickListener(this);    provider = new DataProvider();    diskInfo=new DiskInfo();  }  public void onClick(View v) {    switch (v.getId()) {    case R.id.bt1:        int result = provider.add(3, 5);        Toast.makeText(this, "相加的结果"+result, 1).show();        break;    case R.id.bt2:        String str = provider.sayHelloInC("zhangsan ");        Toast.makeText(this, str, 1).show();        break;    case R.id.bt3:        int[] arr = {1,2,3,4,5};        provider.intMethod(arr);                for(int i=0;i<arr.length;i++){          Toast.makeText(this, "java "+ arr[i], 1).show();            System.out.println("java "+ arr[i]);        }        break;    case R.id.bt4:        int subresult = DataProvider.sub(5, 3);        Toast.makeText(this, "相减的结果"+subresult, 1).show();        break;    case R.id.bt5:      DiskInfo diskInfo=provider.getStruct();      Toast.makeText(this, "结果name:"+diskInfo.getName()+"\nserial:"+diskInfo.getSerial(), 1).show();      break;    }    }}
demo下载地址http://download.csdn.net/detail/maweisky531/9064183



0 0
原创粉丝点击