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

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

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

于 Android NDK 的学习之旅-----数据传输(基本数据类型和数组传输)的更多相关文章

  1. 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据 ...

  2. 基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1.  String 字符串传输 a)         上层定义一个native的方法,需要一个 ...

  3. 基于 Android NDK 的学习之旅-----环境搭建

    工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...

  4. 基于 Android NDK 的学习之旅-----序言

    前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到:   ...

  5. 基于 Android NDK 的学习之旅-----Java 调用C

    随便谈谈为什么要Java调用C 吧: 我认为: 1.  有些公司开发Android项目的时候, 许多组件功能可能是C中已经实现了,所以我们没必要同样的功能又在java中实现一遍.例如我之前做的一个项目 ...

  6. 基于 Android NDK 的学习之旅-----HelloWorld

    Hello World作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此 ...

  7. 基于 Android NDK 的学习之旅-----JNI LOG 打印

    程序都是调出来的. 下面我介绍下JNI层的log打印方法的使用,类似与Android sdk提供的log 1.Android 应用层 MainActivity.java 主要功能代码 a)       ...

  8. 基于 Android NDK 的学习之旅----- C调用Java

    许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现. 下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态 ...

  9. 基于 Android NDK 的学习之旅-----Android.mk 介绍

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

随机推荐

  1. Node.js安装+环境配置【Windows版】

    Node.js安装及环境配置之Windows篇  一.安装环境 1.本机系统:Windows 10 Pro(64位)2.Node.js:v6.9.2LTS(64位) 二.安装Node.js步骤 1.下 ...

  2. BZOJ3238: [Ahoi2013]差异(后缀数组)

    Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 解题思路: 看到lcp,想到了 ...

  3. Spider_scrapy

    多线程爬虫 进程线程回顾 进程 系统中正在运行的一个应用程序 1个CPU核心1次只能执行1个进程,其他进程处于非运行状态 N个CPU核心可同时执行N个任务 线程 进程中包含的执行单元,1个进程可包含多 ...

  4. @property 和@synthesize

    xcode4.4之后,@property包括了@synthesize的功能. 这是编译器的升级. @property有几个作用:1)默认生成一个私有成员变量,并有一个带下划线的别名如_age   2) ...

  5. ViewPager (下)-- 利用 Fragment 实现美丽的 页面切换

    之前用的ViewPager适用于简单的广告切换,但实现页面间的切换最好是用官方推荐的Fragment来处理. 本人力争做到最简单.最有用,是想以后用到的时候能够方便的拿过来复制就能够了. 效果图: w ...

  6. Linux在应用层读写寄存器的方法

    可以通过操作/dev/mem设备文件,以及mmap函数,将寄存器的地址映射到用户空间,直接在应用层对寄存器进行操作,示例如下: #include <stdio.h> #include &l ...

  7. Codeforces Round 363 Div. 1 (A,B,C,D,E,F)

    Codeforces Round 363 Div. 1 题目链接:## 点击打开链接 A. Vacations (1s, 256MB) 题目大意:给定连续 \(n\) 天,每天为如下四种状态之一: 不 ...

  8. StringBuilder和String的区别

      使用   StringBuilder 语言 C# String   对象是不可改变的.每次使用   System.String   类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为 ...

  9. [转]C#连接操作mysql实例

    本文转自:http://hi.baidu.com/zhqngweng/item/c4d2520cb7216877bfe97edf 第三方组件:Mysql.Data.dll说明:去官方网站下载Mysql ...

  10. HibernateCRUD基础框架(3)-简单的和较为复杂的标准的CRUD API

    优点:简单的和基础的CRUD功能可以很快实现,可以说是比较的"标准化".维护起来也很容易. 缺点:性能没有保障.不支持特别复杂的CRUD. 可以适用的场景:小型Web项目 1.Cr ...