序章:
1.本篇是JNI入门教程的第三篇,完整教程连接如下:
2.本篇主要考察的是各种数据类型的转换,要完成的需求如下:
在java层中分别传入int,string,double,char,byte类型,然后在JNI中进行字符串拼接,最终返回给安卓层进行展示。
一。流程步骤
安卓中调用jni主要包含以下几个步骤:
1.在java中声明引用。
2.在jni中创建对应的h文件和cpp文件。
3.在CMakeLists中进行声明,声明之后jni中的方法才能被java外部调用。
4.java层中构造各种数据类型,然后传给JNI进行调用。
二。在java中创建声明类
和上一篇流程一样,所以只贴代码就不详细介绍了:
package com.xt.client.jni;
import com.xt.client.model.JavaModel;
public class CalculationJNITest {
static {
System.loadLibrary("Calculation");
}
/**
* @param value1
* @param value2
* @param str1
* @param double1
* @param chars
* @param bytes
* @return
*/
public native String calculationSum(int value1, int value2, String str1, double double1, char[] chars, byte[] bytes);
}
三。在jni中创建h和cpp文件
1,2流程和上一篇文章中流程是一样的,就不详细介绍了。
1.创建com_xt_client_jni_CalculationJNITest.h文件
2.创建CalculationNative.cpp文件
3.创建JNI中被调用拼接方法Java_com_xt_client_jni_CalculationJNITest_calculationSum
方法如下:
jstring JNICALL
Java_com_xt_client_jni_CalculationJNITest_calculationSum(JNIEnv *env, jobject instance, jint value1,
jint value2, jstring str1, jdouble double1,
jcharArray chars, jbyteArray bytes) {
//因为jni中的字符串是char类型,所以先把第三个参数jstring转换为char类型
const char *thirdStr = env->GetStringUTFChars(str1, 0);
LOGI("%s", "ConvertJcharArray2Chars");
//java中的char类型在JNI中为jcharArray,同样转换为jni中的char类型
char *charsChar = ConvertJcharArray2Chars(env, chars);
LOGI("ConvertJByteaArrayToChars2:%s", charsChar);
//java中的byte类型在JNI中为jbyteArray,同样转换为jni中的char类型
char *bytesChar = ConvertJByteaArrayToChars(env, bytes, charsChar);
LOGI("ConvertJByteaArrayToChars4:%s", charsChar);
LOGI("bytesChar:%s", bytesChar);
//字符串拼接
char *buf = getChar(value1, value2, thirdStr, double1, charsChar, bytesChar);
LOGI("%s %s", "buf is:", buf);
//转换完成中生成jstring类型
jstring computerName = env->NewStringUTF(buf);
//buf已经使用完没用了,进行内存地址的删除
delete[] buf;
return computerName;
}
这里我们发现了好多LOGI,这个是我们自己声明的log方法,主要用于在JNI中调试输出logcat日志,方便排查问题。
我们只需要做如下两部就可以使用了:
1.在CPP文件头部添加声明:
#define LOG_TAG "lxltestjni"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
2.在CMakeLists中创建连接,这个具体第四章会介绍。
4.jint转换为jni中的char类型
使用sprintf()方法进行拼接,
char *getChar(jint value1,
jint value2, const char *str1, jdouble double1,
char *chars, char *bytes) {
char *buf = new char[10];
sprintf(buf, "%i", value1);
LOGI("buff:%s", buf);//1
5.jstring转换为jni中的char类型
可以直接调用JNI提供的方法把jstring转换为char类型
const char *thirdStr = env->GetStringUTFChars(str1, 0);
6.jdouble转换为jni中的char类型
也可以通过sprintf方法进行拼接:
char *getChar(jint value1,
jint value2, const char *str1, jdouble double1,
char *chars, char *bytes) {
char *buf = new char[10];
sprintf(local, "%.0lf", double1);
}
7.jcharArray转换为jni中的char类型:ConvertJcharArray2Chars方法
char *ConvertJcharArray2Chars(JNIEnv *env, jcharArray chars) {
jchar *array = (env)->GetCharArrayElements(chars, NULL);
jsize arraysize = (env)->GetArrayLength(chars);
char *buf = new char[arraysize + 1];
// char buf[arraysize + 1];
LOGI("arraysize:%i", arraysize);
int i = 0;
for (i = 0; i < arraysize; i++) {
buf[i] = static_cast<char>(array[i]);
}
buf[arraysize] = '\0';
return buf;
}
8.jcharByte转换为jni中的char类型
char *ConvertJByteaArrayToChars(JNIEnv *env, jbyteArray bytearray, char *charsChar) {
char *chars = NULL;
jbyte *bytes;
bytes = env->GetByteArrayElements(bytearray, 0);
__android_log_print(0, "111%s", "111");
LOGI("ConvertJByteaArrayToChars3:%s", charsChar);
int chars_len = env->GetArrayLength(bytearray);
LOGI("chars_len:%d", chars_len);
LOGI("ConvertJByteaArrayToChars3.1:%s", charsChar);
chars = new char[chars_len + 1];
LOGI("ConvertJByteaArrayToChars3.2:%s,%s", charsChar, chars);
memset(chars, 0, chars_len + 1);
LOGI("ConvertJByteaArrayToChars3.3:%s,%s", charsChar, chars);
memcpy(chars, bytes, chars_len);
LOGI("ConvertJByteaArrayToChars3.4:%s", charsChar);
chars[chars_len] = 0;
env->ReleaseByteArrayElements(bytearray, bytes, 0);
LOGI("ConvertJByteaArrayToChars3.5:%s", charsChar);
return chars;
}
9.对所有的char字符串进行拼接:getChar方法
四。CMakeLists中做好声明
1.创建文件Cmake文件:
src同级目录下,创建CMakeLists.txt文件,内容如下:逻辑和上一篇文章是一样的。
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library(
Calculation
SHARED
src/main/jni/CalculationNative.cpp)
2.CMakeLists中创建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.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library. 指定连接的目标库
Calculation
# Links the target library to the log library
# included in the NDK.
${log-lib})
3.gradle中做好声明
app的build.gradle文件中,在android{}模块下,添加如下声明:
externalNativeBuild {
cmake {
path "CMakeLists.txt"
// version "3.10.2"
}
}
五。验证效果
1.java中写好调用方法
if (position == 1) {
var calculationJNITest = CalculationJNITest()
val inputStreamFromUrl = IOHelper.fromStringToIputStream("6")
val input2byte = IOHelper.input2byte(inputStreamFromUrl)
try {
val calculationSum =
calculationJNITest.calculationSum(1, 2, "3", 4.0, "5".toCharArray(), input2byte)
mResult.text = calculationSum
} catch (e: Exception) {
e.printStackTrace()
}
return
}
2.点击JNI多类型输入加法(其实应该是多类型输入拼接才对),查看效果,这时候我们发现result中显示了拼接值。
六。项目源码链接:
调用入口类: