* Android NDK JNI 入门笔记目录 *
Java & JNI 基本数据类型
Java 中的基本数据类型包括 boolean,byte,char,short,int,long,float,double 这几种。
而用 C/C++ 编写 native 代码时,是不能直接使用 Java 的数据类型的。
所以 JNI 提供了 jboolean、jbyte、jchar、jshort、jint、jlong、jfloat、jdouble。
Java 基本数据类型与 JNI 数据类型的映射关系
Java Type | Native Type | Description |
---|---|---|
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | N/A |
基本数据类型传递-练习工程
Java -> Native
点击每个按钮,将 Java 的基本数据类型传递到 Native,Native 代码(C/C++)中将数据打印到日志。
JavaToNativeActivity.java
public class JavaToNativeActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java_to_native);
setTitle("Java -> Native");
}
public void booleanTest(View view) {
NativeUtil.javaBooleanToNative(true);
NativeUtil.javaBooleanToNative(false);
}
public void byteTest(View view) {
NativeUtil.javaByteToNative(Byte.MIN_VALUE);
NativeUtil.javaByteToNative(Byte.MAX_VALUE);
NativeUtil.javaByteToNative(Byte.parseByte("123"));
}
public void charTest(View view) {
NativeUtil.javaCharToNative(Character.MIN_VALUE);
NativeUtil.javaCharToNative(Character.MAX_VALUE);
NativeUtil.javaCharToNative('A');
NativeUtil.javaCharToNative('B');
NativeUtil.javaCharToNative('C');
}
public void shortTest(View view) {
NativeUtil.javaShortToNative(Short.MIN_VALUE);
NativeUtil.javaShortToNative(Short.MAX_VALUE);
NativeUtil.javaShortToNative(Short.parseShort("999"));
}
public void intTest(View view) {
NativeUtil.javaIntToNative(Integer.MIN_VALUE);
NativeUtil.javaIntToNative(Integer.MAX_VALUE);
NativeUtil.javaIntToNative(Integer.parseInt("999999"));
}
public void longTest(View view) {
NativeUtil.javaLongToNative(Long.MIN_VALUE);
NativeUtil.javaLongToNative(Long.MAX_VALUE);
NativeUtil.javaLongToNative(Long.parseLong("999999999"));
}
public void floatTest(View view) {
NativeUtil.javaFloatToNative(Float.MIN_VALUE);
NativeUtil.javaFloatToNative(Float.MAX_VALUE);
NativeUtil.javaFloatToNative(999999.8F);
}
public void doubleTest(View view) {
NativeUtil.javaDoubleToNative(Double.MIN_NORMAL);
NativeUtil.javaDoubleToNative(Double.MAX_VALUE);
NativeUtil.javaDoubleToNative(999999999.8);
}
}
NativeUtil.java
public class NativeUtil {
static {
System.loadLibrary("native-lib");
}
public native static void javaBooleanToNative(boolean value);
public native static void javaByteToNative(byte value);
public native static void javaCharToNative(char value);
public native static void javaShortToNative(short value);
public native static void javaIntToNative(int value);
public native static void javaLongToNative(long value);
public native static void javaFloatToNative(float value);
public native static void javaDoubleToNative(double value);
}
native-lib.cpp
#include
#include
#include
#include
#define LOG_TAG "C_TAG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
//LOGD("hello.length=%d",helloLen);
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaBooleanToNative(JNIEnv *env, jclass clazz, jboolean value) {
LOGD("Java Boolean: %d", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaByteToNative(JNIEnv *env, jclass clazz, jbyte value) {
LOGD("Java Byte: %d", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaCharToNative(JNIEnv *env, jclass clazz, jchar value) {
LOGD("Java Char: %d", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaShortToNative(JNIEnv *env, jclass clazz, jshort value) {
LOGD("Java Short: %d", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaIntToNative(JNIEnv *env, jclass clazz, jint value) {
LOGD("Java Int: %d", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaLongToNative(JNIEnv *env, jclass clazz, jlong value) {
LOGD("Java Long: %lld", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaFloatToNative(JNIEnv *env, jclass clazz, jfloat value) {
LOGD("Java Float: %f", value);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaDoubleToNative(JNIEnv *env, jclass clazz, jdouble value) {
LOGD("Java Double: %lf", value);
}
点击每个按钮,在 Logcat 中查看输出日志
D/C_TAG: Java Boolean: 1
D/C_TAG: Java Boolean: 0
D/C_TAG: Java Byte: -128
D/C_TAG: Java Byte: 127
Java Byte: 123
D/C_TAG: Java Char: 0
Java Char: 65535
Java Char: 65
Java Char: 66
Java Char: 67
D/C_TAG: Java Short: -32768
D/C_TAG: Java Short: 32767
Java Short: 999
D/C_TAG: Java Int: -2147483648
Java Int: 2147483647
Java Int: 999999
D/C_TAG: Java Long: -9223372036854775808
Java Long: 9223372036854775807
Java Long: 999999999
D/C_TAG: Java Float: 0.000000
Java Float: 340282346638528859811704183484516925440.000000
Java Float: 999999.812500
D/C_TAG: Java Double: 0.000000
Java Double: 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
Java Double: 999999999.800000
Java <- Navive
点击每个按钮,将从 Native 代码(C/C++)中获取 Java 的基本数据类型。
NativeToJavaActivity.java
public class NativeToJavaActivity extends AppCompatActivity {
private TextView booleanText;
private TextView byteText;
private TextView charText;
private TextView shortText;
private TextView intText;
private TextView longText;
private TextView floatText;
private TextView doubleText;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_native_to_java);
setTitle("Native -> Java");
booleanText = findViewById(R.id.boolean_text);
byteText = findViewById(R.id.byte_text);
charText = findViewById(R.id.char_text);
shortText = findViewById(R.id.short_text);
intText = findViewById(R.id.int_text);
longText = findViewById(R.id.long_text);
floatText = findViewById(R.id.float_text);
doubleText = findViewById(R.id.double_text);
}
public void booleanTest(View view) {
boolean value = NativeUtil.javaBooleanFromNative();
booleanText.setText("value = " + value);
}
public void byteTest(View view) {
byte value = NativeUtil.javaByteFromNative();
byteText.setText("value = " + value);
}
public void charTest(View view) {
char value = NativeUtil.javaCharFromNative();
charText.setText("value = " + value);
}
public void shortTest(View view) {
short value = NativeUtil.javaShortFromNative();
shortText.setText("value = " + value);
}
public void intTest(View view) {
int value = NativeUtil.javaIntFromNative();
intText.setText("value = " + value);
}
public void longTest(View view) {
long value = NativeUtil.javaLongFromNative();
longText.setText("value = " + value);
}
public void floatTest(View view) {
float value = NativeUtil.javaFloatFromNative();
floatText.setText("value = " + value);
}
public void doubleTest(View view) {
double value = NativeUtil.javaDoubleFromNative();
doubleText.setText("value = " + value);
}
}
NativeUtil.java
public class NativeUtil {
static {
System.loadLibrary("native-lib");
}
public native static boolean javaBooleanFromNative();
public native static byte javaByteFromNative();
public native static char javaCharFromNative();
public native static short javaShortFromNative();
public native static int javaIntFromNative();
public native static long javaLongFromNative();
public native static float javaFloatFromNative();
public native static double javaDoubleFromNative();
}
native-lib.cpp
#include
#include
#include
#include
#define LOG_TAG "C_TAG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
//LOGD("hello.length=%d",helloLen);
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaBooleanFromNative(JNIEnv *env, jclass clazz) {
return JNI_TRUE;
}
extern "C"
JNIEXPORT jbyte JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaByteFromNative(JNIEnv *env, jclass clazz) {
return 123;
}
extern "C"
JNIEXPORT jchar JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaCharFromNative(JNIEnv *env, jclass clazz) {
return 'A';
}
extern "C"
JNIEXPORT jshort JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaShortFromNative(JNIEnv *env, jclass clazz) {
return 999;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaIntFromNative(JNIEnv *env, jclass clazz) {
return 999999;
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaLongFromNative(JNIEnv *env, jclass clazz) {
return 999999999;
}
extern "C"
JNIEXPORT jfloat JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaFloatFromNative(JNIEnv *env, jclass clazz) {
return 999999.8;
}
extern "C"
JNIEXPORT jdouble JNICALL
Java_com_ihubin_ndkjni_NativeUtil_javaDoubleFromNative(JNIEnv *env, jclass clazz) {
return 999999999.8;
}
点击每个按钮,进行测试
Java <-> Native
点击每个按钮,将和 Native(C/C++) 传递、获取 Java 的基本数据类型。
JavaNativeActivity.java
public class JavaNativeActivity extends AppCompatActivity {
private TextView charConcatText;
private TextView sumText;
private TextView twoExpText;
private TextView calcMoneyText;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java_native);
setTitle("Java <-> Native");
charConcatText = findViewById(R.id.char_concat_text);
sumText = findViewById(R.id.sum_text);
twoExpText = findViewById(R.id.two_exp_text);
calcMoneyText = findViewById(R.id.calc_money_text);
}
public void charConcatTest(View view) {
String value = NativeUtil.charConcatTest('A', 'B', 'C');
charConcatText.setText("A+B+C=" + value);
}
public void sumTest(View view) {
int numOne = 123;
int numTwo = 456;
int value = NativeUtil.sumText(numOne, numTwo);
sumText.setText(numOne + "+" + numTwo + "=" + value);
}
public void twoExpTest(View view) {
int value = NativeUtil.twoExpTest(10);
twoExpText.setText("2^10=" + value);
}
public void calcMoneyTest(View view) {
double apple = 12.4;
double banana = 99.8;
double orange = 101.1;
String value = NativeUtil.calcMoneyTest(apple, banana, orange);
calcMoneyText.setText(value);
}
}
NativeUtil.java
public class NativeUtil {
static {
System.loadLibrary("native-lib");
}
public native static String charConcatTest(char a, char b, char c);
public native static int sumText(int i, int j);
public native static int twoExpTest(int exp);
public native static String calcMoneyTest(double v, double v1, double v2);
}
native-lib.cpp
#include
#include
#include
#include
#define LOG_TAG "C_TAG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
//LOGD("hello.length=%d",helloLen);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_ihubin_ndkjni_NativeUtil_charConcatTest(JNIEnv *env, jclass clazz, jchar a, jchar b,
jchar c) {
char charArray[4];
charArray[0] = a;
charArray[1] = b;
charArray[2] = c;
charArray[3] = '\0';
return env->NewStringUTF(charArray);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ihubin_ndkjni_NativeUtil_sumText(JNIEnv *env, jclass clazz, jint i, jint j) {
return i + j;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_ihubin_ndkjni_NativeUtil_twoExpTest(JNIEnv *env, jclass clazz, jint exp) {
return pow(2, exp);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_ihubin_ndkjni_NativeUtil_calcMoneyTest(JNIEnv *env, jclass clazz, jdouble v, jdouble v1,
jdouble v2) {
double totalMoney = v + v1 + v2;
char *resultStr = new char();
sprintf(resultStr, "总计:%f", totalMoney);
return env->NewStringUTF(resultStr);
}
点击每个按钮,进行测试
至此,我们已经学会了在 Android 项目中与 Native(C/C++) 进行数据交换。
代码:
NDKJNIday02
参考资料:
Oracle - JNI Types and Data Structures
JNI 打印 log 信息