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