于 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) 获取 数组里面的元素:
- (*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.
- (*env)->GetIntArrayRegion(env,array,start,len,buffer) , 从start开始复制长度为len 的数据到buffer中
5) 设置 数组里面的元素
- (*env)->SetIntArrayRegion(env, array,start,len,buffer) , 从start开始复制长度为len 的数据 buffer到 array 中
有不理解的兄弟请留言,个人技术有限,有讲错的地方请大牛们指出,讲的不够全面的请多多包涵,谢谢,
点击下载源码 数据的传输一
本文出自 duicky博客 , 转载请注明出处 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/19/2145486.html
于 Android NDK 的学习之旅-----数据传输(基本数据类型和数组传输)的更多相关文章
- 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)
原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据 ...
- 基于 Android NDK 的学习之旅-----数据传输(引用数据类型)
接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1. String 字符串传输 a) 上层定义一个native的方法,需要一个 ...
- 基于 Android NDK 的学习之旅-----环境搭建
工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...
- 基于 Android NDK 的学习之旅-----序言
前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到: ...
- 基于 Android NDK 的学习之旅-----Java 调用C
随便谈谈为什么要Java调用C 吧: 我认为: 1. 有些公司开发Android项目的时候, 许多组件功能可能是C中已经实现了,所以我们没必要同样的功能又在java中实现一遍.例如我之前做的一个项目 ...
- 基于 Android NDK 的学习之旅-----HelloWorld
Hello World作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此 ...
- 基于 Android NDK 的学习之旅-----JNI LOG 打印
程序都是调出来的. 下面我介绍下JNI层的log打印方法的使用,类似与Android sdk提供的log 1.Android 应用层 MainActivity.java 主要功能代码 a) ...
- 基于 Android NDK 的学习之旅----- C调用Java
许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现. 下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态 ...
- 基于 Android NDK 的学习之旅-----Android.mk 介绍
一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...
随机推荐
- C# Unity依赖注入利用Attribute实现AOP功能
使用场景? 很多时候, 我们定义一个功能, 当我们要对这个功能进行扩展的时候, 按照常规的思路, 我们一般都是利用OOP的思想, 在原有的功能上进行扩展. 那么有没有一种东西, 可以实现当我们需要扩展 ...
- HDU 4927 Series 1(推理+大数)
HDU 4927 Series 1 题目链接 题意:给定一个序列,要求不断求差值序列.直到剩一个,输出这个数字 思路:因为有高精度一步.所以要推理一下公式,事实上纸上模拟一下非常easy推出公式就是一 ...
- IIS7性能优化
http://www.03389.com/BLOG/user1/qq66565841/archives/2014/2014112143553.html IIS7性能优化 IIS7 优化-网站请求并发数 ...
- solr6.3+tomcat8报错HTTP Status 403 – Forbidden解决办法
注释掉tomcat下solr项目web.xml中的如下这段代码即可:
- 无法显式调用运算符或访问器 错误处理方法 DLL study
无法显式调用运算符或访问器 错误处理方法 转 无法显式调用运算符或访问器 错误处理方法 反汇编一个dll类库,导出的项目会报出很多bug,其中主要的就是“无法显式调用运算符或访问器”这个错误,看了一下 ...
- SpringMVC学习总结(2)——SpringMVC返回json配置
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 --> <bean id="mappingJacksonHttpMessageConverter" c ...
- 【Codeforces Round #301 (Div. 2) C】 Ice Cave
[链接] 我是链接,点我呀:) [题意] 给你一个n*m的地图. 每个地图为0的时候可以安全走过,且走过后变成1. (一定要离开之后才会变成1) 而为1的则走过之后会掉入下一层. 你一开始在初始位置( ...
- Hadoop笔记(一)
1.大数据的概述 大数据:巨量数据.海量数据,首先在数据的量上达到一定的规模,首先是人或者计算机在不合理时间内是不能够实现的数据量. 2.特点:数据量比较大,数据类型多样化.处理速度问题 3.大数据平 ...
- Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument
spring 5.+jpa 配置类出错: 十二月 20, 2018 5:53:01 下午 org.springframework.web.servlet.DispatcherServlet initS ...
- 表单提交数据格式form data
前言: 最近遇到的最多的问题就是表单提交数据格式问题了. 常见的三种表单提交数据格式,分别举例说明:(项目是vue的框架) 1.application/x-www-form-urlencoded 提交 ...