zoukankan      html  css  js  c++  java
  • 于 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

  • 相关阅读:
    Mina入门demo
    MySQL数据库插入中文时出现Incorrect string value: 'xE6x97xB7xE5x85xA8' for column 'sz_name' at row 1
    synchronized和volatile
    springboot+Zookeeper+Dubbo入门
    zookeeper的安装
    windows下dubbo-admin的安装
    Java 枚举类
    Mysql 解压版 安装时候的注意事项
    Java——JDBC鶸笔记
    《初识Java微信公众号开发》 学习中遇到的困难
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6148283.html
Copyright © 2011-2022 走看看