android开发 在JNI函数中引用Java类,将cxx复杂数据转换成jobjectArray,实现从JNI到Java的数据传输

本文详细介绍了如何在Android开发中,通过JNI从C++层引用Java类,并将复杂C++数据转换成jobjectArray,实现在JNI到Java之间的数据传输。步骤包括定义Java接口类、使用FindClass找到对应的C++接口、初始化C++接口类、在JNI函数中进行数据转换,以及CMakeLists配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言:

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} )

代码可见我的github
项目地址:https://github.com/Steven9402/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值