基於 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 <[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 ismade; 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章