2016年3月6日 星期日

Android 開發筆記 - 在 Android NDK/JNI 環境中,操作 HashMap 和 Vector 方法與資料型態定義

過去在 C++ 把玩 std::vector<std::unordered_map<int, std::string>> ,而搬到 Java 環境中時,就會出現檔案形態的轉變,於是乎就先挑個 Vector<HashMap<String,String>> 來試試,順手筆記一下。

其中 JNI 在呼叫 Java 物件時,Java 八大型態及 Java Class 型態在 JNI 中採用的關鍵字:

Java boolean type => "Z"
Java byte type => "B"
Java char type => "C"
Java short type => "S"
Java int type => "I"
Java long type => "J"
Java float type => "F"
Java double type => "D"
Java object type => "Ljava/lang/Object;"
Java Array of int type => "[I"
Java Array of double type => "[D"
Java Array of java/lang/Object type => "[Ljava/lang/Object;"


舉例來說,以 Vector 的 public boolean add(E e) 函數為例:

jclass vectorClass = env->FindClass("java.util.Vector");
jmethodID vector_add = env->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z");


其中 "(Ljava/lang/Object;)Z" 代表此函式回傳為 boolean 型態,而需要傳遞一個 java/lang/Object 當作參數。

最後是比較冗長的操作:

Java code:

static {
System.loadLibrary("test")
}
public native boolean test(Vector<HashMap<String, String>> obj);

void usage() {

Vector<HashMap<String, String>> output = new Vector<HashMap<String, String>>();
boolean ret = test(output);
Log.i(tag, "Ret: "+ret+", output size: "+output.size());
}


build.gradle (Module:app):

android.ndk {
moduleName = "test"
ldLibs.addAll(["log"])
CFlags.add("-std=c++11")
stl = "c++_shared"
}


C/C++ code:

#include <jni.h>
#include <android/log.h>

#define LOG_TAG "JNI"
#define LOGV(...)__android_log_print( ANDROID_LOG_VERBOSE,LOG_TAG, __VA_ARGS__ )
#define LOGD(...)__android_log_print( ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__ )
#define LOGI(...)__android_log_print( ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__ )
#define LOGW(...)__android_log_print( ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__ )
#define LOGE(...)__android_log_print( ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__ )

extern "C" {


jboolean Java_YourPackageName_test(JNIEnv *env, jobject thiz, jobject vectorObject) {

jclass vectorClass = env->GetObjectClass(vectorObject);
jmethodID vector_size = env->GetMethodID(vectorClass, "size", "()I");
jmethodID vector_add = env->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z");
jmethodID vector_elementAt = env->GetMethodID(vectorClass, "elementAt", "(I)Ljava/lang/Object;");

jclass hashMapClass = env->FindClass("java/util/HashMap");
jmethodID hashMap_init = env->GetMethodID(hashMapClass, "<init>", "(I)V");
jmethodID hashMap_put = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
jmethodID hashMap_get = env->GetMethodID(hashMapClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
jmethodID hashMap_size = env->GetMethodID(hashMapClass, "size", "()I");

std::unordered_map<int, std::string> attrs;
attrs[0] = "Hello";
attrs[1] = "World";

if (vectorObject && vectorClass && hashMapClass) {
// init HashMap object
jobject dataHashMap = env->NewObject(hashMapClass, hashMap_init, 1);
for (auto it = attrs.begin(); it != attrs.end(); ++it) {
jstring key = env->NewStringUTF(std::to_string(it->first).c_str());
jstring value = env->NewStringUTF(it->second.c_str());
env->CallObjectMethod(dataHashMap, hashMap_put, key, value);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
LOGI("hashmap size: %d", env->CallIntMethod(dataHashMap, hashMap_size));

LOGI("vector size: %d", env->CallIntMethod(vectorObject, vector_size));

// vector add
env->CallBooleanMethod(vectorObject, vector_add, dataHashMap);
env->DeleteLocalRef(dataHashMap);

// access vector
for (int i=0, cnt = env->CallIntMethod(vectorObject, vector_size) ; i<cnt; ++i) {
LOGI("get vector_elementAt: %d", i);
if (vector_elementAt) {
jobject dataInVector = env->CallObjectMethod(vectorObject, vector_elementAt, i);
jclass dataInVectorClass = env->GetObjectClass(dataInVector);
jmethodID dataInVector_get = env->GetMethodID(dataInVectorClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
if (dataInVector && dataInVector_get) {
jstring key = env->NewStringUTF(std::to_string(0).c_str());
jstring value = (jstring)env->CallObjectMethod(dataInVector, dataInVector_get, key);
LOGI("get vector_elementAt: %d, value: [%s]", i, value);
env->DeleteLocalRef(key);
}
}
}

}


return false;
}

}

沒有留言:

張貼留言