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

标签: android ndk 学习 | 发表时间:2011-08-19 11:26 | 作者:duicky UnderSn0w
出处:http://www.cnblogs.com/

基于 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 <[email protected]>
 *
 */
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

 

作者: duicky 发表于 2011-08-19 11:26 原文链接

评论: 0 查看评论 发表评论


最新新闻:
· comScore:7月谷歌独立访问用户1.823亿 居第一(2011-08-20 09:24)
· Steven Levy:“Google 特立独行”(2011-08-20 09:22)
· 我们在做俯卧撑(2011-08-20 09:20)
· 微软诉摩托罗拉侵权案听证会下周一开庭(2011-08-20 09:09)
· 谷歌地图将提供全球天气预报和云覆盖区信息(2011-08-20 09:08)

编辑推荐:挥手作别,HP 写下 webOS 的休止符

网站导航:博客园首页  我的园子  新闻  闪存  小组  博问  知识库

相关 [android ndk 学习] 推荐:

android NDK的学习

- - CSDN博客推荐文章
NDK是基于系统原生的C/C++的开发,但是它不是一种主流,而是Android SDK开发的有益补充,因为NDK没有提供界面,也没有提供生命周期管理这一类环境. NDK是一系列的工具包,使用这些工具包能够让我们很方便的进行JNI的开发. Java native interface,JNI就是java和C/C++相互调用的接口.

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

- UnderSn0w - 博客园-首页原创精华区
基于 Android NDK 的学习之旅-----数据传输(基本数据类型和数组传输).        之前的一些文章都有涉及到上层和中间层的数据传输,简单来说,也就是参数和返回值的使用. 因为中间层要做的最多的也就是数据传输与转换,下面来介绍下这方面的知识.        数据传输可分为 基本数据类型传输 和 引用数据类型的传输 , 因为数组传输也比较特别(其实数组也是引用类型),所以这里也专门分出来讲讲.

Android NDK开发Crash错误定位

- - 极客521 | 极客521
在Android开发中,程序Crash分三种情况:未捕获的异常、ANR(Application Not Responding)和闪退(NDK引发错误). 其中 未捕获的异常根据logcat打印的堆栈信息很容易定位错误. ANR错误也好查,Android规定,应用与用户进行交互时,如果5秒内没有响应用户的操作,则会引发ANR错误,并弹出一个系统提示框,让用户选择继续等待或立即关闭程序.

Android 之 JNI 开发 详解 - NDK从入门到精通

- - CSDN博客推荐文章
-- 第一个JNI示例程序下载 :  GitHub - https://github.com/han1202012/NDKHelloworld.git . JNI概念 : Java本地接口, Java Native Interface, 它是一个 协议, 该协议用来沟通Java代码和外部的本地C/C++代码, 通过该协议 Java代码可以调用外部的本地代码, 外部的C/C++ 代码可以调用Java代码;.

Android NDK开发扫盲及最新CMake的编译使用 - 简书

- -
本篇文章旨在简介 Android 中. NDK是什么以及重点讲解最新 Android Studio 编译工具. NDK之前还是首推 Android 官方. 官方文档分别从以下几个方面介绍了. ABI是什么以及不同 CPU 指令集支持哪些. 如何使用您自己及其他预建的库. 所以建议先浏览一遍文档,或者看完本篇文章再回头看一遍文档.

android学习路线图

- Enlizh - Starming星光社最新更新
      首先表扬一下iteye,本来想把这些文章发表在CSDN(虽然都是一家的). 但发现CSDN博客功能用户体验做的不是那么友好,图片压缩的太厉害. 好好的图片上传之后已经面目全非. 只好又再iteye注册了个相同的博客,当然内容也相同. 做android开发有一段时间了,一直想挤出点时间,写点什么.

Android学习之路——7.Service

- - ITeye博客
这两天又学习了Android四大组件之一的Service. (1)Service不是一个单独的Process,除非特别指派了,也不是一个Thread,但也不是运行在Main Thread中. (3)Service的生命周期:. 调用的Context.startService()   oncreate() --> onStartCommand ()--> Service is running --> The service is stopped by its or a client--> onDestroy() --> Service is shut down .

Android学习笔记(六)SQLite

- - 博客园_首页
SQLite是一个极轻量型的数据库. 它在提供了和大型数据库相当的功能,还具有轻便、跨平台等优点,SQLite使用非常方便,并不需要我们像常规数据库(SQLServer,Mysql等)那样进行安装,在Android的JDK中,其实是已经包含了SQLite这个数据库的核心. 当然我们必须要强调一点,SQLite并不是只针对Android的,其实它还可以用在别的很多地方.

Android Native 代码开发学习笔记

- iDesperadO - WindStorm
本文提供排版更佳的PDF版本下载. JNI,全称Java Native Interface,是用于让运行在JVM中的Java代码和运行在JVM外的Native代码(主要是C或者C++)沟通的桥梁. 代码编写者即可以使用JNI从Java的程序中调用Native代码,又可以从Native程序中调用Java代码.

Android学习笔记之Gallery(2)

- - CSDN博客推荐文章
Toast.makeText(GalleryActivity.this, "点击了第"+arg2+"张图片", Toast.LENGTH_LONG).show();. // 给ImageView设置资源. // 设置布局 图片120*80. 创建一个新的XML文件在 res/values/目录下 attrs.xml命名.