顯示具有 hashmap 標籤的文章。 顯示所有文章
顯示具有 hashmap 標籤的文章。 顯示所有文章

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

}

2016年3月4日 星期五

Android 開發筆記 - 從 Java 端傳遞 HashMap 物件 Android NDK/ JNI C/C++ 操作變更內容

C/C++ Code:

#include <jni.h>

extern "C" {

jobject Java_YourPackageName_updateHashMap(JNIEnv *env, jobject thiz, jobject hashmap) {
    if (!hashmap)
        return hashmap;

    jclass mapClass = env->GetObjectClass(hashmap);
    jmethodID obj_put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

    if (mapClass && obj_put) {
        jstring key = env->NewStringUTF("Haha");
        jstring value = env->NewStringUTF("Hehe");
        env->CallObjectMethod(hashmap, obj_put, key, value);
        env->DeleteLocalRef(key);
        env->DeleteLocalRef(value);
    }

    return hashmap;
}
}


Android Java code:

public native HashMap updateHashMap(HashMap<String, String>map);
static {
        System.loadLibrary("native");
}

void usage() {
HashMap<String, String> mHashMap = new HashMap<String, String>();

        Log.d(tag, "HashMap size: "+mHashMap.size());
updateHashMap(mHashMap);
        Log.d(tag, "HashMap size: "+mHashMap.size());

        Iterator it = mHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry)it.next();
            Log.d(tag, "HashMap key: ["+pair.getKey()+"], value: ["+pair.getValue().toString()+"]");
        }
}

Android 開發筆記 - 使用 Android NDK / JNI 回傳 HashMap 物件至 Java 端

C/C++ Code:

#include <jni.h>

extern "C" {

jobject Java_YourPackageName_getHashMap(JNIEnv *env, jobject thiz) {

    jclass mapClass = env->FindClass("java/util/HashMap");
    jmethodID obj_init = env->GetMethodID(mapClass, "<init>", "(I)V");
    jmethodID obj_put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    jobject hashMap = env->NewObject(mapClass, obj_init, 1);

    /*
    const char * input_data = "HelloWorld";
    int input_data_length = strlen(input_data);

    jbyteArray data = env->NewByteArray(input_data_length);
    env->SetByteArrayRegion(data, 0, input_data_length, (const jbyte *)input_data);
    env->CallObjectMethod(hashMap, obj_put, (jbyteArray)data, (jbyteArray)data);
    env->DeleteLocalRef(data);
    */
    jstring key = env->NewStringUTF("Hello");
    jstring value = env->NewStringUTF("World");
    env->CallObjectMethod(hashMap, obj_put, key, value);
    env->DeleteLocalRef(key);
    env->DeleteLocalRef(value);

    //env->DeleteLocalRef(hashMap);
    return hashMap;
}

}


Android Java code:

public native HashMap getHashMap();
static {
        System.loadLibrary("native");
}

void usage() {
HashMap<String, String> mHashMap = getHashMap();

        Log.d(tag, "HashMap size: "+mHashMap.size());
        Log.d(tag, "HashMap data with key(Hello): "+mHashMap.get("Hello"));
        Iterator it = mHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry)it.next();
            Log.d(tag, "HashMap key: ["+pair.getKey()+"], value: ["+pair.getValue().toString()+"]");
        }
}