基于 Android NDK 的学习之旅-----数据传输一(基本数据类型和数组传输)(附源码)

基于 Android NDK 的学习之旅-----数据传输(基本数据类型和数组传输)

 

       之前的一些文章都有涉及到上层和中间层的数据传输,简单来说,也就是参数和返回值的使用。因为中间层要做的最多的也就是数据传输与转换,下面来介绍下这方面的知识。

       数据传输可分为 基本数据类型传输 引用数据类型的传输 因为数组传输也比较特别(其实数组也是引用类型),所以这里也专门分出来讲讲。

 

1、主要流程

1、  基本数据类型的传输

a)         上层定义一个native的方法,需要一个int 参数 ,返回一个int

b)        JNI 对应 上层的方法 打印出  上层 传输下来的 int数据,并返回 int数据

c)         上层 收到 native 方法 返回的 值,在UI中显示出来

 

 

2、  数组的传输

a)         上层定义一个native的方法,需要一个int数组,返回一个int数组

b)        JNI 对应上层的方法,取出上层传递数组中的数据处理和打印出来,并存入新数组中,最后把该数组返回给 Java

c)         上层 收到 native返回的 数组,加工成字符串,在UI中显示出来

 

 

2设计实现

1、  界面设计如下:


老老样子,很搓,嘿嘿

代码不在这贴出了,有需要的兄弟直接到文章结束部分下载。

2、  关键代码说明

 

Java 上层:

   

 public native int getDoubleNumber(int num);

public native int[] getArrayDoubleNumber(int[] nums);

  MainActivity.java

  

package com.duicky;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/**
 * 数据传输
 * 
 * @author luxiaofeng <454162034@qq.com>
 *
 */
public class MainActivity extends Activity {
	
	//也就是你mk配置文件中的  LOCAL_MODULE    := NDK_06
	private static final String libSoName = "NDK_06";
	private Context mContext = null;
	
	private int num = 0;
	private int[] nums;
	
	private Button btnCalculate = null;
	private Button btnCalculateArray = null;
	private EditText etNum = null;
	private EditText etArrayNum = null;
	private TextView tvDoubleNum = null;
	private TextView tvArrayDoubleNum = null;
	
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mContext = this;
        initViews();
    }
    
    /**
     * 初始化控件
     */
    private void initViews() {
		btnCalculate = (Button) findViewById(R.id.btn_calculate);
		btnCalculateArray = (Button) findViewById(R.id.btn_calculate_array);
		etNum = (EditText) findViewById(R.id.et_num);
		etArrayNum = (EditText) findViewById(R.id.et_array_num);
		tvDoubleNum = (TextView) findViewById(R.id.tv_double_num);
		tvArrayDoubleNum = (TextView) findViewById(R.id.tv_array_double_num);
		btnCalculate.setOnClickListener(new MyOnClickListener());
		btnCalculateArray.setOnClickListener(new MyOnClickListener());
	}

    private void calculateArray() {
    	if(getArrayNums()) {
    		setArrayNums();
    	}
	}

	private void calculate() {
		if(getNum()){
			setNum();
		}
	}
	
	private boolean getNum(){
		try{
			num = Integer.valueOf(etNum.getText().toString());
		} catch(NumberFormatException e) {
			etNum.setText("");
			tvDoubleNum.setText("");
			LogUtils.toastMessage(mContext, "输入有误,请重新输入数字");
			return false;
		}
		return true;
	}
	
	private void setNum() {
		int doubleNum = getDoubleNumber(num);
		LogUtils.printWithLogCat("JNIMsg", "C JNI -- >  Java: num = "+doubleNum);
		tvDoubleNum.setText(String.valueOf(doubleNum));
	}
	
	private boolean getArrayNums() {
		String str = etArrayNum.getText().toString();
		if(str.length() <= 0) {
			etArrayNum.setText("");
			tvArrayDoubleNum.setText("");
			LogUtils.toastMessage(mContext, "请按照格式输入");
			return false;
		}
		System.out.println(str);
		if(str.endsWith(".")){
			str = str.substring(0, str.length()-2);
		}
		System.out.println(str);
		String[] strArray = str.split(",");
		int len = strArray.length;
		nums = new int[len];
		for (int i = 0; i < len; i++) {
			try {
				nums[i] = Integer.valueOf(strArray[i]);
				System.out.println(nums[i]);
			} catch(NumberFormatException e) {
				etArrayNum.setText("");
				tvArrayDoubleNum.setText("");
				LogUtils.toastMessage(mContext, "输入有误,请重新输入数组");
				return false;
			}
		}
		return true;
	}
    
	private void setArrayNums() {
		int[] doubleArrayNums = getArrayDoubleNumber(nums);
		
		if(doubleArrayNums == null || doubleArrayNums.length <= 0) {
			LogUtils.toastMessage(mContext, "未转化成功");
			return ;
		}
		
		String str = "";
		for (int i = 0; i < doubleArrayNums.length; i++) {
			str += doubleArrayNums[i] +".";
		}
		str = str.substring(0,str.length()-1);
		tvArrayDoubleNum.setText(str);
	}
	
   class MyOnClickListener implements OnClickListener{

		@Override
		public void onClick(View v) {
			switch(v.getId()) {
				case R.id.btn_calculate:
					calculate();
					break;
				case R.id.btn_calculate_array:
					calculateArray();
					break;
			}
		}
    }

	/**
     * 计算2倍的数字
     * 
     * @param num
     * 
     * @return
     */
    public native int getDoubleNumber(int num);
    
    
    /**
     * 计算2倍的数组值
     * 
     * @param num
     * 
     * @return
     */
    public native int[] getArrayDoubleNumber(int[] nums);
    
    /**
     * 载入JNI生成的so库文件
     */
    static {
        System.loadLibrary(libSoName);
    }
}

  

       定义两个native方法, 第一个是 用来 测试传输 基本数据类型的,第二个是用来测试 传输数组的。

      

       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_06

LOCAL_SRC_FILES := \

Transmission.c

include $(BUILD_SHARED_LIBRARY)

  

老样子,不说了,你懂的。 如果不懂,嘎嘎,那就请点击Android.mk 文件 简介咯

 

       JNI 中间层

      

       Transmission.c

      

#include <string.h>
#include <jni.h>
#include <android/log.h>

JNIEnv* jniEnv;


jint
Java_com_duicky_MainActivity_getDoubleNumber( JNIEnv* env,jobject thiz,jint num )
{
	if(jniEnv == NULL) {
		jniEnv = env;
	}
	//获取 Java 传递下来 数字
	__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "Java -- > C JNI : num = %d",num);
	//返回 2 倍 的数字给 Java
	return num*2;
}

jintArray
Java_com_duicky_MainActivity_getArrayDoubleNumber( JNIEnv* env,jobject thiz,jintArray nums )
{
	if(jniEnv == NULL) {
		jniEnv = env;
	}

	if(nums == NULL){
		return NULL;
	}

	//获取 Java 传递下来 数组 的 长度
	jsize len = (*jniEnv)->GetArrayLength(jniEnv, nums);

	__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "Java -- > C JNI : len = %d",len);

	if(len <= 0) {
		return NULL;
	}

	//新建一个长度为len的jintArray数组
	jintArray array = (*jniEnv)-> NewIntArray(jniEnv, len);

	if(array == NULL) {
		return NULL;
	}

	// 把 Java 传递下来的数组 用 jint* 存起来
	jint *body = (*env)->GetIntArrayElements(env, nums, 0);

	jint i = 0;
	jint num[len];
	for (; i < len; i++) {
		num[i] = body[i] * 2;
		__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "Java -- > C JNI : nums[%d] = %d",i,num[i]);
	}

	if(num == NULL){
		return NULL;
	}

	//给 需要返回的数组赋值
	(*jniEnv)->SetIntArrayRegion(jniEnv,array, 0, len, num);

	return array;
}

  

3、运行结果

测试 基本数据类型传输: 输入 22 点击 计算 得出结果 44


 

查看 打印 信息 :看到 上层输出 结果


 

测试 引用数据类型传输:输入11,22,33,44,55  ( 逗号是在英文状态下半角输入) ,点击生成, 输出 22,44,66,88,100


查看 打印信息  看到JNI层输出 结果


 

 

以上就是 Java --- JNI  基本数据类型 数组 传输的  小例子 , 其他 基本数据类型和数组 都可以仿照上面的做法传输。

 

 

 

4、注意点

你必须知道的是:

1)  添加参数在(JNIEnv* env,jobject thiz) 后面添加 如:(JNIEnv* env,jobject thiz,jintArray nums )

2)  获取数组的长度 jsize len = (*jniEnv)->GetArrayLength(jniEnv, nums);

3)  新建数组 jintArray array = (*jniEnv)-> NewIntArray(jniEnv, len); 如果是新建别的数组,NewIntArray 要做相对应的改变

4)  获取 数组里面的元素:

1.         (*env)->GetIntArrayElements(env, nums, isCopy) , 返回 所有数据。If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; if no copy is made, it is set to JNI_FALSE.

2.          (*env)->GetIntArrayRegion(env,array,start,len,buffer) , start开始复制长度为len 的数据到buffer

5)  设置 数组里面的元素

1.         (*env)->SetIntArrayRegion(env, array,start,len,buffer) , start开始复制长度为len 的数据 buffer array

 

 

有不理解的兄弟请留言,个人技术有限,有讲错的地方请大牛们指出,讲的不够全面的请多多包涵,谢谢,

 

点击下载源码 数据的输一

 

本文出自 duicky 博客  转载请注明出处 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/19/2145486.html

 

posted on 2011-08-19 11:26  陆晓峰  阅读(13195)  评论(4编辑  收藏  举报

导航