JNI中用long傳遞指針到java

JNI給我們提供了很多類型來保證java與C++中的統(tǒng)一,像是jint,jlong等等,但是很多時候這些類型不能滿足我們的需要。而且Android中我們總是希望C++是用來做高效處理使用的,但是我們并不希望過多的業(yè)務邏輯在C++中做,比如像我們要批量對一個文件或者一片數(shù)據(jù)來做處理,那我們在java中做的話肯定要用到多線程來做這個事情,我們希望多線程是在java控制的,但是內存我們希望在C++中開辟。

比如我們想得到一個std::map<int, std::vector<int> >,但是要多次調用才能把vector<float>塞到std::map<int, std::vector<int> >里面,我們可以在第一次調用的時候開辟這個std::map<int, std::vector<int> >,但是怎么在后續(xù)的調用中繼續(xù)找到它并朝這塊內存中塞數(shù)據(jù)呢?這里就引出了我們今天的內容:
我們可以開辟完std::map<int, std::vector<int> >之后把它的指針強轉為一個long傳回java層。
其實Android源碼里面也有很多這樣操作的例子,比如Android的ClassLoader去load dex的時候就用了這種方式:
Android中的ClassLoader分析

std::map<int, std::vector<int> > *map = new std::map<int, std::vector<int> >();

JNIEXPORT jlong JNICALL JNI_METHOD_NAME(getVectorAddr)(JNIEnv *env, jclass type, jint index) {
    return (long) map;
}

為什么可以這樣轉換呢?
我們知道指針在32位的機器上是4個字節(jié)的,一個字節(jié)是8位,32 = 8 ?? 4,所以32位的最大尋址是4GB。那64位的機器上指針則是8個字節(jié),一個long完全可以存儲。
其實我們把這個指針傳回java,java是完全不知道這個有什么意義的。其實java也不需要知道這個有什么意義,因為這只是一塊內存的地址。java只需要記住這個地址,下次調用的時候帶著這個long過來調用就好了。
我們說了,這個long其實就是一塊地址,我們把這個long強轉為double或者float或者其他8位以上的類型都沒有問題,因為我們使用的時候知道這其實是一塊地址的首地址就好了,那我們把它強轉為vector<vector<float> > *,我們就知道我們當前操作的是哪塊地址了。

JNIEXPORT void JNICALL JNI_METHOD_NAME(getVector)(JNIEnv *env, jclass type, jlong addr) {
    std::map<int, std::vector<int> > *newMap = (std::map<int, std::vector<int> > *) addr;
}

那我們既然拿到了之前開辟的我們繼續(xù)在這里做其他需要的操作就好了。

#include <jni.h>
#include <string>
#include <vector>
#include <map>
#include<android/log.h>

#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,"yoyo_JNI_utils",__VA_ARGS__)

#define JNI_METHOD_NAME(name) Java_com_yocn_mycapplication_nativelib_NativeJni_##name

extern "C" {
JNIEXPORT void JNICALL JNI_METHOD_NAME(init)(JNIEnv *env, jclass type, jint size);
JNIEXPORT jlong JNICALL JNI_METHOD_NAME(getVectorAddr)(JNIEnv *env, jclass type, jint index);
JNIEXPORT void JNICALL JNI_METHOD_NAME(getVector)(JNIEnv *env, jclass type, jlong addr);
}

std::map<int, std::vector<int> > *map = new std::map<int, std::vector<int> >();

JNIEXPORT void JNICALL JNI_METHOD_NAME(init)(JNIEnv *env, jclass type, jint size) {
    for (int i = 0; i < size; i++) {
        std::vector<int> *vector = new std::vector<int>();
        for (int j = 0; j < 10; ++j) {
            vector->push_back(j * 10);
        }
        map->insert(std::pair<int, std::vector<int> >(i, *vector));
    }
    u_long mapSize = map->size();
    LOGE("mapSize---->%ld", mapSize);
    for (int i = 0; i < map->size(); ++i) {
        std::vector<int> child = (*map)[i];
        LOGE("child %d->%ld", i, child.size());
    }
}

JNIEXPORT jlong JNICALL JNI_METHOD_NAME(getVectorAddr)(JNIEnv *env, jclass type, jint index) {
    return (long) map;
}

JNIEXPORT void JNICALL JNI_METHOD_NAME(getVector)(JNIEnv *env, jclass type, jlong addr) {
    std::map<int, std::vector<int> > *newMap = (std::map<int, std::vector<int> > *) addr;
    u_long mapSize = newMap->size();
    LOGE("new mapSize---->%ld", mapSize);
    LOGE("%ld", addr);
    for (int i = 0; i < newMap->size(); ++i) {
        std::vector<int> child = (*newMap)[i];
        LOGE("a  child %d->%ld", i, child.size());
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容