android開發 在JNI函式中引用Java類,將cxx複雜資料轉換成jobjectArray,實現從JNI到Java的資料傳輸
阿新 • • 發佈:2019-02-12
引言:
JNI是Java可以呼叫高效的c++程式碼,但是在JNI函式中傳遞複雜資料型別十分的繁瑣,一般情況下需要jobject作為中轉,一維陣列int[],float[]以及二維陣列String[]可以實現方便的引數傳入/傳出。其他複雜的二、三維陣列理論上可以使用jobjectarray實現引數傳入/傳出,可是實現過程中出現問題,可能是記憶體上的錯誤。
下面介紹一種通用方法,在JNI函式中引用Java類,將cxx複雜資料轉換成jobjectArray,實現從JNI到Java的資料傳輸。
Step1:定義Java類介面
這裡定義了一個目標檢測的通用介面類。建立”OneDetection.java”如下:
package com.example.cuizhou.test01;
import android.graphics.Bitmap;
/**
* Created by cuizhou on 18-1-11.
*/
public class OneDetection {
private String mLabel;
private float mConfidence;
private int mLeft;
private int mTop;
private int mRight;
private int mBottom;
public OneDetection() {
}
/**
* @param label Label name
* @param confidence A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
* @param l The X coordinate of the left side of the result
* @param t The Y coordinate of the top of the result
* @param r The X coordinate of the right side of the result
* @param b The Y coordinate of the bottom of the result
*/
public OneDetection(String label, float confidence, int l, int t, int r, int b) {
mLabel = label;
mLeft = l;
mTop = t;
mRight = r;
mBottom = b;
mConfidence = confidence;
}
/**
* @return The X coordinate of the left side of the result
*/
public int getLeft() {
return mLeft;
}
/**
* @return The Y coordinate of the top of the result
*/
public int getTop() {
return mTop;
}
/**
* @return The X coordinate of the right side of the result
*/
public int getRight() {
return mRight;
}
/**
* @return The Y coordinate of the bottom of the result
*/
public int getBottom() {
return mBottom;
}
/**
* @return A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
*/
public float getConfidence() {
return mConfidence;
}
/**
* @return The label of the result
*/
public String getLabel() {
return mLabel;
}
public Bitmap getDetBitmap(Bitmap resBitmap){
//Bitmap dstBitmap=Bitmap.createBitmap(10,10,Bitmap.Config.ARGB_8888);
// todo: cropBitmap 不安全 //這裡建立了一個10*10的黑色bitmap,後面改成更加合理的方案。
Bitmap dstBitmap = BitmapProcess.cropBitmap(resBitmap, mLeft, mTop,mRight-mLeft,mBottom-mTop);
return dstBitmap;
}
}
Step2:使用FindClass定義對應的c++介面
建立”jniTest.h”如下:
//
// Created by cuizhou on 18-1-15.
//
#ifndef TEST01_JNITEST_H
#define TEST01_JNITEST_H
#include <jni.h>
#include <android/log.h>
#include <string>
#define CLASSNAME_VISION_DET_RET "com/example/cuizhou/test01/OneDetection"
#define CONSTSIG_VISION_DET_RET "()V"
class JNI_VisionDetRet {
public:
JNI_VisionDetRet(JNIEnv* env) {
jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET);
jID_label = env->GetFieldID(detRetClass, "mLabel", "Ljava/lang/String;");
jID_confidence = env->GetFieldID(detRetClass, "mConfidence", "F");
jID_left = env->GetFieldID(detRetClass, "mLeft", "I");
jID_top = env->GetFieldID(detRetClass, "mTop", "I");
jID_right = env->GetFieldID(detRetClass, "mRight", "I");
jID_bottom = env->GetFieldID(detRetClass, "mBottom", "I");
}
void setLabel(JNIEnv* env, jobject& jDetRet, const std::string& label) {
jstring jstr = (jstring)(env->NewStringUTF(label.c_str()));
env->SetObjectField(jDetRet, jID_label, (jobject)jstr);
}
void setRect(JNIEnv* env, jobject& jDetRet, const int& left, const int& top,
const int& right, const int& bottom) {
env->SetIntField(jDetRet, jID_left, left);
env->SetIntField(jDetRet, jID_top, top);
env->SetIntField(jDetRet, jID_right, right);
env->SetIntField(jDetRet, jID_bottom, bottom);
}
static jobject createJObject(JNIEnv* env) {
jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET);
jmethodID mid =
env->GetMethodID(detRetClass, "<init>", CONSTSIG_VISION_DET_RET);
return env->NewObject(detRetClass, mid);
}
static jobjectArray createJObjectArray(JNIEnv* env, const int& size) {
jclass detRetClass = env->FindClass(CLASSNAME_VISION_DET_RET);
return (jobjectArray)env->NewObjectArray(size, detRetClass, NULL);
}
private:
jfieldID jID_label;
jfieldID jID_confidence;
jfieldID jID_left;
jfieldID jID_top;
jfieldID jID_right;
jfieldID jID_bottom;
};
#endif //TEST01_JNITEST_H
Step3: 初始化C++介面類JNI_VisionDetRet
建立”jni_utils.cpp”,首先定義了一個
JNI_VisionDetRet* g_pJNI_VisionDetRet;
(作用未知)然後使用
JNI_OnLoad
方法初始化JNI_VisionDetRet
,後面在c++函式中就可以呼叫JNI_VisionDetRet
中的方法。
#include <string>
#include "jniTest.h"
#include <sstream>
#include <unistd.h>
// Java Integer/Float
JNI_VisionDetRet* g_pJNI_VisionDetRet;
JavaVM* g_javaVM = NULL;
//初始化類g_pJNI_VisionDetRet
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
g_javaVM = vm;
JNIEnv* env;
vm->GetEnv((void**)&env, JNI_VERSION_1_6);
g_pJNI_VisionDetRet = new JNI_VisionDetRet(env);
return JNI_VERSION_1_6;
}
void JNI_OnUnload(JavaVM* vm, void* reserved) {
g_javaVM = NULL;
delete g_pJNI_VisionDetRet;
}
Step4:在JNI函式中通過介面類將c++資料轉化成jobjectArray,實現資料傳輸。
建立native-lib.cpp
#include <jni.h>
#include <string>
#include "../jni/jniCommon/jniTest.h"
extern JNI_VisionDetRet* g_pJNI_VisionDetRet; //extern 作用未知
extern "C"
JNIEXPORT jobjectArray
JNICALL
Java_com_example_cuizhou_test01_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
jobjectArray jDetRetArray = JNI_VisionDetRet::createJObjectArray(env, 4);
for(int ind=0;ind<4;ind++){
jobject jDetRet = JNI_VisionDetRet::createJObject(env);
env->SetObjectArrayElement(jDetRetArray, ind, jDetRet);//在這裡吧jDetRet放入了jDetRetArray
g_pJNI_VisionDetRet->setRect(env, jDetRet, 11,12,
123, 345);//向jDetRet新增rect
g_pJNI_VisionDetRet->setLabel(env, jDetRet, "car");//向jDetRet新增label
}
return jDetRetArray;
}
相應的Java中的JNI函式:
public native OneDetection[] getDetection();
Step5: CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp
src/main/jni/jniCommon/jni_utils.cpp)
find_library( log-lib
log )
target_link_libraries( native-lib
${log-lib} )