許多成熟的C引擎要移植到Android 平臺上使用 , 一般都會 提供 一些接口, 讓Android sdk 和 jdk 實現。
下文將會介紹 C 如何 通過 JNI 層調用 Java 的靜態和非靜態方法。
1、主要流程
1、 新建一個測試類TestProvider.java
a) 該類提供了2個方法
b) 一個靜態的方法,一個非靜態的方法
2、 JNI中新建Provider.c
a) 該文件中需要把Java中的類TestProvider映射到C中
b) 把TestProvider的兩個方法映射到C中
c) 新建TestProvider 對象
d) 調用兩個方法
3、 Android 上層 調用 JNI層
4、 JNI層調用C層
5、 C 層調用 Java 方法
2、設計實現
1、界面設計如下:
老樣子,很搓,不過實用,嘿嘿
代碼不在這貼出了,有需要的兄弟直接到文章結束部分下載。
2、 關鍵代碼說明
C中定義映射的類、方法、對象
jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;
C 中映射 類
TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
C中新建對象
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider,"<init>", "()V");
TestProvider mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);
C 中映射方法
靜態:
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
非靜態:
sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");
C 中調用 Java的 方法
靜態:
(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
非靜態:
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
注意 GetXXXMethodID 和 CallXXXMethod 。
第一個XXX 表示的是映射方法的類型,如: 靜態 跟非靜態
第二個 XXX 表示 調用方法的返回值 ,如:Void,Object,等等。(調用靜態方法的時候Call後面要加Static)
詳細 映射方法 和 調用方法 請參考 JNI 文檔 ,這個很重要 !
3、 Java 上層 關鍵代碼
TestProvider.Java 的兩個方法
public class TestProvider { |
public static String getTime() { |
LogUtils.printWithSystemOut( "Call From C Java Static Method" ); |
LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Static Method" ); |
return String.valueOf(System.currentTimeMillis()); |
public void sayHello(String msg) { |
LogUtils.printWithSystemOut( "Call From C Java Not Static Method :" + msg); |
LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method :" + msg); |
4、 Android.mk 文件 關鍵代碼
LOCAL_PATH := $(call my-dir) |
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include |
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog |
include $(BUILD_SHARED_LIBRARY) |
老樣子,不說了,你懂的。 如果不懂,嘎嘎,那就請點擊Android.mk 文件 簡介
5、 JNI文件夾下文件
Provider.h
Provider.c
int GetProviderInstance(jclass obj_class); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 1" ); |
if (TestProvider == NULL) { |
TestProvider = (*jniEnv)->FindClass(jniEnv, "com/duicky/TestProvider" ); |
if (TestProvider == NULL){ |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 2 ok" ); |
if (mTestProvider == NULL) { |
if (GetProviderInstance(TestProvider) != 1) { |
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 3 ok" ); |
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime" , "()Ljava/lang/String;" ); |
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); |
(*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 4 ok" ); |
sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello" , "(Ljava/lang/String;)V" ); |
(*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); |
(*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); |
(*jniEnv)->DeleteLocalRef(jniEnv, getTime); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 5 ok" ); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 6" ); |
int GetProviderInstance(jclass obj_class) { |
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class, |
if (construction_id == 0) { |
mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class, |
if (mTestProvider == NULL) { |
if (TestProvider == NULL || getTime == NULL) { |
int result = InitProvider(); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "GetTime Begin" ); |
jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime); |
cstr = ( char *) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "Success Get Time from Java , Value = %s" ,cstr ); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "GetTime End" ); |
(*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr); |
(*jniEnv)->DeleteLocalRef(jniEnv, jstr); |
* SayHello ---- 調用 Java 方法 |
if (TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) { |
int result = InitProvider() ; |
jstrMSG =(*jniEnv)->NewStringUTF(jniEnv, "Hi,I'm From C" ); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "SayHello Begin" ); |
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG); |
__android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "SayHello End" ); |
(*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG); |
CToJava.c
* Java 中 聲明的native getTime 方法的實現 |
void Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz) |
* Java 中 聲明的native sayHello 方法的實現 |
void Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz) |
3、運行效果
1、點擊 “C調用java靜態方法”按鈕
C成功調用了Java中的getTime 方法,通過C方法打印出上層調用得到的時間,並且上層成功吐司出調用信息出來。
2、點擊 “C調用java非靜態方法”按鈕
C成功調用了sayHello 方法, 併成功接收到 C 傳遞的參數,和 吐司出相對應的信息
4、C調用Java注意點
a) C 映射java 方法時 對應的簽名
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
故事情節還沒發展這麼快,下一章纔會專門介紹下這個簽名的使用
b)映射方法的時候需要區別靜態和非靜態GetStaticMethodID,GetMethodID
c)調用的時候也需要區分CallStaticObjectMethod,CallVoidMethod 而且還需要區分返回值類型
點擊下載源碼 C調用Java例子
本文出自 duicky 博客
, 轉載請註明出處 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html