2012年4月19日 星期四

Java Native Interface (JNI) Android C呼叫Java (底層呼叫上層)間傳遞篇--以靜態或動態類型為例


在"Java Native Interface (JNI)入門 -- 觀念篇"這篇文章中實作二C呼叫JAVA部份說明當 C 呼叫 Java 需要建立一個  JVM 通道,然後透過Get----MethodID 搭配 Call----MethodID獲取JAVA中的指定參數。
本篇學習重點在於如何在Android NDK中由C呼叫Java。

 C呼叫Java會遇到的機會通常在於Java程式比C好寫清況或是將舊有C程式的移植時發生。
執行情況大致下列兩種:
 1.Java 進入C後,C再回到Java 呼叫函數。
 2.Java 進入C; C產生thread然後由這個thread回到Java 呼叫函數。


一般來說完成上述功能,會透過Get----MethodID搭配Call----Method方法來完成,
其中Get----MethodID 中 --- 表示的是對應(Mapping)方法的靜態(Static)或動態(non-Static)類型。
而 CallStatic<Type>Method或Call <Type> Method 中  <Type>  表示的是呼叫(Call)方法的返回值 ,例如:Int、Char、Void、Object、...等。

例如:
呼叫 JAVA 靜態類型:
(*jniEnv)->GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);   <-- C Mapping
(*jniEnv)->CallStatic <Type> Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);        <-- C call Java

呼叫 JAVA 動態類型:
(*jniEnv)->GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);             <-- C Mapping
(*jniEnv)->Call <Type> Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);                  <-- C call Java

至於詳細的對應(Mapping)與呼叫(Call)方法,三言兩語不太可能講完的,詳細資訊可在網路上搜尋 "The Java Native Interface Programmer’s Guide and Specification" 的一個 PDF檔案內容中有更詳細的說明(查文件最後的Index)。


實作一、靜態呼叫
程式碼:
JAVA:
 C:

結果:






實作二、動態呼叫
程式碼:
Java:
 C:

結果:




參考:
1.The Java Native Interface Programmer’s Guide and Specification
http://java.sun.com/docs/books/jni/
2.給新手 - static 成員
http://www.javaworld.com.tw/jute/post/view?bid=29&id=11490&sty=1&tpg=1&age=-1
===========延伸閱讀========================================
第一支Android NDK程式--HelloJni

Java Native Interface (JNI) 的使用時機及影響

Java Native Interface (JNI)入門 -- 觀念篇

Java Native Interface (JNI) 實戰篇

Java Native Interface (JNI) Android實戰篇(使用NDK) -- HelloUart

Java Native Interface (JNI) Android算數篇(使用NDK) -- Fibonacci Sequence

Java Native Interface (JNI) Android C++語言篇--以Hello-JNI為例

Java Native Interface (JNI) Android C++語言篇--以Hello-JNI為例

Java Native Interface (JNI) Android C程式間傳遞篇--以two-libs為例

Java Native Interface (JNI) Android C呼叫Java (底層呼叫上層)間傳遞篇--以靜態或動態類型為例

Android NDK Beginner’s Guide

4 則留言:

  1. 你好 我用hellojni來修改成實作1 , 在跑模擬時出現Unfortunately,HelloJni has stopped ,程式碼部份都如上修改,唯一可能會不同的地方剩xml檔,我是只有留一個Button用的部份,請問蚊子大有辦法幫我解惑一下嗎??還是說jni不行這樣直接修改?

    初學jni還不是很了解,麻煩您了,感謝您!!

    回覆刪除
    回覆
    1. 您先看一下Logcat錯誤訊息,我的經驗很多都是void後面的參數沒有按照Android規範來寫:
      Java_Android Package Name_類名稱_native函數名,並注意底線及大小寫
      如果不知道怎麼寫才對,很多人都是產生出*.h檔來看內容,部落格有一篇你可以參考看看如何產生h檔
      http://cheng-min-i-taiwan.blogspot.tw/2012/08/javah-jni-c-h.html

      刪除
  2. 感謝你~~我果然有些大小寫寫錯了。
    在修改了之後剩下__android_log_print會無法辨識的問題,解決辦法是在android.mk檔裡的include $(CLEAR_VARS)下行增加LOCAL_LDLIBS := -lm -llog再儲存就可以了,希望能幫助到^^

    回覆刪除