之前的一些文章都有涉及到上層和中間層的數據傳輸,簡單來說,也就是參數和返回值的使用。因為中間層要做的最多的也就是數據傳輸與轉換,下面來介紹下這方面的知識。
數據傳輸可分為 基本數據類型傳輸 和 引用數據類型的傳輸 , 因為數組傳輸也比較特別(其實數組也是引用類型),所以這裡也專門分出來講講。
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 博客