android-ndk 数据传递

首先定义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 __cplusplus
extern "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"); //String
	jstring 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; //c99
	for (; 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值