2015. 4. 24. 11:18

몇년 만에 블로그에 손을 대게 되다니;;;;;;

이번 삽질을 통해 몇 가지 알게 된 사실입니다.


1. JNI 함수를 만들 때 매개변수의 개수와 순서에 유의해야 한다.
첫번째 매개변수는 JNIEnv, 두번째 매개변수는 jclass 또는 jobject 여야 한다.
세번째 부터는 사용자가 JNI에서 제공되는 data type 내에서 마음껏(?) 지정할 수 있다.


2. JNI 함수에서 기본 data type의 array(예> int[], byte[] 등)가 아닌 ArrayList를 사용해야 할 땐 다음와 같이 한다.아래 코드는 2중 ArrayList(?)의 형태를 띈 ArrayList<AAA>의 최하위 요소인 test1, test2를 가져오는 코드이다.

  1. // ---------- AAA.java ----------
  2. public class AAA {
  3.         public int itemID;
  4.         public ArrayList<BBB>   bbb;
  5. }
  6.  
  7. // ---------- BBB.java ----------
  8. public class BBB {
  9.         public int test1;
  10.         public int test2;
  11. }
  12.  
  13. // ---------- JNI 함수 호출을 위한 Java Interface ----------
  14. public class Natives {
  15.         public static native void JNICallTest(ArrayList<AAA> list);
  16. }


---------- JNI 함수 구현부 ---------

  1. JNIEXPORT void JNICALL Java_com_test_app_jni_Natives_JNICallTest(JNIEnv *env, jobject thisObj, jobject objArrayListAAA)
  2. {
  3.         // ArrayList<AAA> 형식의 클래스 가져오기
  4.         jclass clsArrayListAAA = env->FindClass("java/util/ArrayList");
  5.  
  6.         // ArrayList의 멤버함수인 size, get을 사용하기 위해 methodID를 가져오기
  7.         // 아래에서 얻어온 메소드ID로 ArrayList<AAA>와 ArrayList<BBB> 등, 모든 ArrayList<type> 형식의 size, get 함수 사용이 가능하다.
  8.         jmethodID midSize = env->GetMethodID(clsArrayListAAA, "size""()I");
  9.         jmethodID midGet = env->GetMethodID(clsArrayListAAA, "get""(I)Ljava/lang/Object;");
  10.  
  11.         // ArrayList<AAA>에서 AAA 클래스 가져오기
  12.         jobject objAAA = env->CallObjectMethod(objArrayListAAA, midGet, 0);
  13.         jclass clsAAA = env->GetObjectClass(objAAA);
  14.  
  15.         // AAA 클래스의 필드 가져오기
  16.         // 필드의 값을 얻어오는 게 아니라, 필드 ID를 얻어와서 나중에 필드의 값을 얻어올 때 사용한다.
  17.         jfieldID fidItemID = env->GetFieldID(clsAAA, "itemID""I");
  18.         jfieldID fidArrayListBBB = env->GetFieldID(clsAAA, "bbb""Ljava/util/ArrayList;");
  19.         jobject objArrayListBBB = env->GetObjectField(objAAA, fidArrayListBBB);
  20.  
  21.         // ArrayList<BBB> 에서 BBB 클래스 가져오기
  22.         jobject objBBB = env->CallObjectMethod(objArrayListBBB, midGet, 0);
  23.         jclass clsBBB = env->GetObjectClass(objBBB);
  24.  
  25.         // BBB 클래스의 필드 가져오기
  26.         jfieldID fidTest1 = env->GetFieldID(classBBB, "test1""I");
  27.         jfieldID fidTest2 = env->GetFieldID(classBBB, "test2""I");
  28.  
  29.         // 중첩 for문으로 ArrayList<AAA>의 모든 하위정보 가져오기
  30.         int lengthAAA = env->CallIntMethod(objArrayListAAA, midSize);
  31.         for(int ii = 0; ii < lengthAAA; ii++)
  32.         {
  33.                 jobject _objAAA = env->CallObjectMethod(objArrayListAAA, midGet, ii);
  34.  
  35.                 int itemID = env->GetIntField(_objAAA, fidItemID);
  36.                 jobject _objArrayListBBB = env->GetObjectField(_objAAA, fidArrayListBBB);
  37.                
  38.                 int lengthBBB = env->CallIntMethod(_objArrayListBBB, midSize);
  39.                 for(int jj = 0; jj < lengthBBB; jj++)
  40.                 {
  41.                         jobject _objBBB = env->CallObjectMethod(_objArrayListBBB, midGet, ii);
  42.                        
  43.                         int test1 = env->GetIntField(_objBBB, fidTest1);
  44.                         int test2 = env->GetIntField(_objBBB, fidTest2);
  45.                        
  46.                         // 이런 loop구조에서는 반드시 해제해주어야 함!!!
  47.                         // 굳이 loop가 아니어도 함수 내에서 많은 양의 jobject나 jclass등을
  48.                         // 가져와서 사용해야 한다면 사용이 끝난 것들은 해제해주는 것이 좋다.
  49.                         env->DeleteLocalRef(_objBBB);
  50.                 }
  51.                
  52.                 // loop 안에서 가져온 것들은 반드시 해제!!
  53.                 // 나중에 Release<type>ArrayElements 형식의 함수와 같이 사용하게 됐을 때
  54.                 // 덜 헷갈리려면 가져올 때와 역순으로 해제해주는 것이 좋다.
  55.                 env->DeleteLocalRef(_objArrayListBBB);
  56.                 env->DeleteLocalRef(_objAAA);
  57.         }
  58.  
  59.         // 이 아래 것들은 함수가 끝나면 자동으로 해제되므로
  60.         // 굳이 해제해주지 않아도 되지만 왠지 모를 찝찝함 때문에 해제 ^^;;
  61.         env->DeleteLocalRef(clsBBB);
  62.         env->DeleteLocalRef(objBBB);
  63.  
  64.         env->DeleteLocalRef(objArrayListBBB);
  65.  
  66.         env->DeleteLocalRef(clsAAA);
  67.         env->DeleteLocalRef(objAAA);
  68.  
  69.         env->DeleteLocalRef(clsArrayListAAA);
  70. }


Posted by 허늬