jni新手笔记四:jni数据类型
基础类型
java类型 | jni类型 | 签名 |
---|---|---|
boolean | jboolean | Z |
byte | jbyte | B |
char | jchar | C |
short | jshort | S |
int | jint | I |
long | jlong | J |
float | jfloat | F |
double | jdouble | D |
复杂类型
image.pngjni对象
的的签名规则为 L类路径;
,例如jstring
的签名为 Ljava/lang/String;
数组的签名规则为 [类型
,例如int[]
签名是[I
, long[]
签名是[L
有了java
与jni
变量对象
的对应关系及其签名
,就可以知道在jni
中如何使用了,下面做几个简单演示。
在这之前先在jni
中引入Android
的log
库,以便在logcat
中输出运行结果。根据你选择的编译类型在 Android.mk
或 CMakeLists.txt
中引入Android
log
库
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 库名
LOCAL_MODULE := hello
LOCAL_SRC_FILES := src/main/ndk/ndktest.cpp \
src/main/ndk/hello.cpp
# 使用系统log
LOCAL_LDLIBS :=-llog
include $(BUILD_SHARED_LIBRARY)
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library. 库名
hello
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/ndk/hello.cpp
src/main/ndk/ndktest.cpp)
# Specifies a path to native header files.
include_directories(src/main/ndk/)
# 使用系统log
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
# {sdk-path}/ndk-bundle/sysroot/usr/include/android/log.h
log )
target_link_libraries( # Specifies the target library.
hello
# Links the target library to the log library
# included in the NDK.
${log-lib} )
在ndktest.cpp
中定义几个宏,方便使用
#include<android/log.h>
#define TAG "jni-ndktest"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
一、基础变量
java
类 NDKTest
中新增方法 primitiveTest
/**
* jni 基础类型测试
*
* @param params1
* @param params2
* @param params3
* @return
*/
public int primitiveTest(float params1, int params2, boolean params3) {
Log.i(TAG, "primitiveTest params1:" + params1
+ " params2:" + params2
+ " params3:" + params3);
return 100;
}
ndktest.cpp
中新增方法int callPrimitiveMethod(JNIEnv *, jobject);
调用 java
方法primitiveTest
/**
* 基础变量测试
* @param pEnv
* @param obj
* @return
*/
int callPrimitiveMethod(JNIEnv *pEnv, jobject obj) {
jclass testClass = pEnv->GetObjectClass(obj);
jmethodID methodID = pEnv->GetMethodID(testClass, "primitiveTest", "(FIZ)I");
jint result = pEnv->CallIntMethod(obj, methodID, 15.f, 100, true);
LOGI("callPrimitiveMethod result:%d", result);
return 0;
}
在Java_com_don_ndk_NDKTest_getHello
中调用 callPrimitiveMethod
方法
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
jstring result = pEnv->NewStringUTF(getHello());
// callObjectMethod(pEnv, obj);
// callStaticMethod(pEnv, obj);
callPrimitiveMethod(pEnv, obj);
return result;
}
运行程序,logcat
中输出
I/NDKTest: primitiveTest params1:15.0 params2:100 params3:true
I/jni-ndktest: callPrimitiveMethod result:100
二、jstring
在java
类 NDKTest
中新增方法 stringTest
/**
* jni jstring 测试
*
* @param params1
* @param params2
* @return
*/
public String stringTest(String params1, String params2) {
Log.i(TAG, "stringTest params1:" + params1 + " params2:" + params2);
return params1 + " " + params2;
}
在ndktest.cpp
中新增方法int calljstringMethod(JNIEnv *, jobject);
调用 java
方法stringTest
/**
* jstring测试
* @param pEnv
* @param obj
* @return
*/
int calljstringMethod(JNIEnv *pEnv, jobject obj) {
jclass testClass = pEnv->GetObjectClass(obj);
jmethodID methodID = pEnv->GetMethodID(testClass, "stringTest",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
jstring result = (jstring) pEnv->CallObjectMethod(obj, methodID, pEnv->NewStringUTF("幸福"),
pEnv->NewStringUTF("安康"));
const char *charResult = pEnv->GetStringUTFChars(result, JNI_FALSE);
LOGI("calljstringMethod result:%s", charResult);
pEnv->ReleaseStringUTFChars(result, charResult);
return 0;
}
在Java_com_don_ndk_NDKTest_getHello
中调用 方法calljstringMethod
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
jstring result = pEnv->NewStringUTF(getHello());
// callObjectMethod(pEnv, obj);
// callStaticMethod(pEnv, obj);
// callPrimitiveMethod(pEnv, obj);
calljstringMethod(pEnv, obj);
return result;
}
运行程序,logcat
中输出
I/NDKTest: stringTest params1:幸福 params2:安康
I/jni-ndktest: calljstringMethod result:幸福 安康
三、数组
在java
类 NDKTest
中新增方法 arrayTest
/**
* jni 数组测试
*
* @param array
* @return
*/
public String[] arrayTest(int[] array) {
String[] resultArray = new String[array.length];
for (int i = 0; i < array.length; i++) {
resultArray[i] = "array index " + i + " is " + array[i];
}
return resultArray;
}
在ndktest.cpp
中新增方法 callArrayMethod
调用java
方法arrayTest
/**
* 数组测试
* @param pEnv
* @param obj
* @return
*/
int callArrayMethod(JNIEnv *pEnv, jobject obj) {
jclass testClass = pEnv->GetObjectClass(obj);
jmethodID methodID = pEnv->GetMethodID(testClass, "arrayTest", "([I)[Ljava/lang/String;");
jint buf[] = {10, 20, 30, 40, 50};
jintArray intArray = pEnv->NewIntArray(5);
pEnv->SetIntArrayRegion(intArray, 0, 5, buf);
jobjectArray resultArray = (jobjectArray) pEnv->CallObjectMethod(obj, methodID, intArray);
for (int i = 0; i < pEnv->GetArrayLength(resultArray); i++) {
jstring result = (jstring) pEnv->GetObjectArrayElement(resultArray, i);
const char *charResult = pEnv->GetStringUTFChars(result, JNI_FALSE);
LOGI("callArrayMethod index %d is %s", i, charResult);
pEnv->ReleaseStringUTFChars(result, charResult);
}
return 0;
}
在Java_com_don_ndk_NDKTest_getHello
中调用方法callArrayMethod
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
jstring result = pEnv->NewStringUTF(getHello());
// callObjectMethod(pEnv, obj);
// callStaticMethod(pEnv, obj);
// callPrimitiveMethod(pEnv, obj);
// calljstringMethod(pEnv, obj);
callArrayMethod(pEnv, obj);
return result;
}
运行程序,logcat
中输出
I/jni-ndktest: callArrayMethod index 0 is array index 0 is 10
I/jni-ndktest: callArrayMethod index 1 is array index 1 is 20
I/jni-ndktest: callArrayMethod index 2 is array index 2 is 30
I/jni-ndktest: callArrayMethod index 3 is array index 3 is 40
I/jni-ndktest: callArrayMethod index 4 is array index 4 is 50
四、自定义对象
新增对象TestBean
,用以测试jni
调用对象
package com.don.ndk;
public class TestBean {
public TestBean() {
}
public String name;
public int score;
public float money;
@Override
public String toString() {
return "TestBean{" +
"name='" + name + '\'' +
", score=" + score +
", money=" + money +
'}';
}
}
在java
类 NDKTest
中新增方法 objTest
/**
* jni 自定义对象测试
*
* @param testBean
* @return
*/
public TestBean objTest(TestBean testBean) {
Log.i(TAG, "objTest " + testBean);
TestBean resultBean = new TestBean();
resultBean.name = "小红";
resultBean.score = 100;
resultBean.money = 1000000.f;
return resultBean;
}
在ndktest.cpp
中新增方法int callObjMethod(JNIEnv *, jobject);
调用 java
方法objTest
/**
* jobject测试
* @param pEnv
* @param obj
* @return
*/
int callObjMethod(JNIEnv *pEnv, jobject obj) {
jclass testClass = pEnv->GetObjectClass(obj);
jmethodID methodID = pEnv->GetMethodID(testClass, "objTest",
"(Lcom/don/ndk/TestBean;)Lcom/don/ndk/TestBean;");
// 获取TestBean的类
jclass beanClass = pEnv->FindClass("com/don/ndk/TestBean");
// 获取TestBean的构造方法,TestBean中一定要有显式的构造方法
jmethodID initMethodID = pEnv->GetMethodID(beanClass, "<init>", "()V");
jfieldID nameFiledID = pEnv->GetFieldID(beanClass, "name", "Ljava/lang/String;");
jfieldID scoreFiledID = pEnv->GetFieldID(beanClass, "score", "I");
jfieldID moneyFiledID = pEnv->GetFieldID(beanClass, "money", "F");
// 构造TestBean对象
jobject testBean = pEnv->NewObject(beanClass, initMethodID);
// 给TestBean对象赋值
jstring name = pEnv->NewStringUTF("小明");
pEnv->SetObjectField(testBean, nameFiledID, name);
pEnv->DeleteLocalRef(name);
pEnv->SetIntField(testBean, scoreFiledID, 60);
pEnv->SetFloatField(testBean, moneyFiledID, -10000.f);
jobject result = pEnv->CallObjectMethod(obj, methodID, testBean);
// 获取返回对象中的值
jstring resultName = (jstring) pEnv->GetObjectField(result, nameFiledID);
const char *charResultName = pEnv->GetStringUTFChars(resultName, JNI_FALSE);
jint resultScore = pEnv->GetIntField(result, scoreFiledID);
jfloat resultMoney = pEnv->GetFloatField(result, moneyFiledID);
LOGI("callObjMethod result name:%s score:%d money:%f", charResultName, resultScore,
resultMoney);
pEnv->ReleaseStringUTFChars(resultName, charResultName);
return 0;
}
这里需要特别强调一点,因为这里构造TestBean
对象使用的是TestBean
的默认方法,所以在TestBean
中一定要有显式的构造方法,否则jni
找不到方法,会崩溃
在Java_com_don_ndk_NDKTest_getHello
中调用方法callObjMethod
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
jstring result = pEnv->NewStringUTF(getHello());
// callObjectMethod(pEnv, obj);
// callStaticMethod(pEnv, obj);
// callPrimitiveMethod(pEnv, obj);
// calljstringMethod(pEnv, obj);
// callArrayMethod(pEnv, obj);
callObjMethod(pEnv, obj);
return result;
}
运行程序,logcat
中输出
I/NDKTest: objTest TestBean{name='小明', score=60, money=-10000.0}
I/jni-ndktest: callObjMethod result name:小红 score:100 money:1000000.000000