基於 Android NDK 的學習之旅----- C調用Java

基於 Android NDK 的學習之旅----- C調用Java

許多成熟的C引擎要移植到Android 平臺上使用 , 通常都會 提供 一些接口Android sdk  jdk 實現。 html

下文將會介紹 C 如何 經過 JNI 層調用 Java 的靜態和非靜態方法。 java

 

一、主要流程

一、  新建一個測試類TestProvider.java android

a)         該類提供了2個方法 shell

b)        一個靜態的方法,一個非靜態的方法 ide

二、  JNI中新建Provider.c 學習

a)         該文件中須要把Java中的類TestProvider映射到C 測試

b)        TestProvider的兩個方法映射到C ui

c)         新建TestProvider 對象 spa

d)        調用兩個方法 設計

三、  Android 上層 調用 JNI

四、  JNI層調用C

五、  層調用 Java 方法

 

2、設計實現

1、界面設計以下:


老樣子,很搓,不過實用,嘿嘿

代碼不在這貼出了,有須要的兄弟直接到文章結束部分下載。

 

 

二、      關鍵代碼說明

C中定義映射的類、方法、對象

jclass TestProvider;

jobject mTestProvider;

jmethodID getTime;

jmethodID sayHello;

 

中映射 

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

中映射方法

       靜態:

getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");

       非靜態:

sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");

中調用 Java 方法

       靜態:

(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);

       非靜態:

(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);

 

注意 GetXXXMethodID   CallXXXMethod 

第一個XXX 表示的是映射方法的類型,如: 靜態 跟非靜態

第二個 XXX 表示 調用方法的返回值 ,如:Void,Object,等等。(調用靜態方法的時候Call後面要加Static

 

詳細 映射方法  調用方法 請參考 JNI 文檔 ,這個很重要 

 

三、      Java 上層 關鍵代碼

TestProvider.Java 的兩個方法

package com.duicky;
 
/**
 *
 *
 * @author luxiaofeng <454162034@qq.com>
 *
 */
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);
    }
 
}



四、      Android.mk 文件 關鍵代碼


LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
 
 
LOCAL_MODULE    := NDK_04
LOCAL_SRC_FILES := \
CToJava.c \
Provider.c
 
include $(BUILD_SHARED_LIBRARY)


老樣子,不說了,你懂的。 若是不懂,嘎嘎,那就請點擊Android.mk 文件 簡介

 

 

五、      JNI文件夾下文件

Provider.h

?
#include <string.h>
#include <jni.h>
 
void GetTime() ;
void SayHello();


 

Provider.c  




#include "Provider.h"
#include <android/log.h>
 
extern JNIEnv* jniEnv;
 
jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;
 
int GetProviderInstance(jclass obj_class);
 
/**
 * 初始化 類、對象、方法
 */
int InitProvider() {
 
    __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  1" );
 
    if(jniEnv == NULL) {
        return 0;
    }
 
    if(TestProvider == NULL) {
        TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
        if(TestProvider == NULL){
            return -1;
        }
        __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  2 ok" );
    }
 
    if (mTestProvider == NULL) {
        if (GetProviderInstance(TestProvider) != 1) {
            (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
            return -1;
        }
        __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  3 ok" );
    }
 
    if (getTime == NULL) {
        getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider,"getTime","()Ljava/lang/String;");//()表示參數爲空,Ljava/lang/String表示返回值爲String類型
     if (getTime == NULL) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
            (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
            return -2;
        }
        __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  4 ok" );
    }
    if (sayHello == NULL) {
        sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider,"sayHello","(Ljava/lang/String;)V");//(Ljava/lang/String表示參數是String類型,V表示返回值是void類型)
        if (sayHello == NULL) {
            (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
            (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
            (*jniEnv)->DeleteLocalRef(jniEnv, getTime);
            return -3;
        }
        __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  5 ok" );
    }
    __android_log_print(ANDROID_LOG_INFO,"JNIMsg","InitProvider Begin  6" );
    return 1;
}
int GetProviderInstance(jclass obj_class) {
    if(obj_class == NULL) {
        return 0;
    }
    jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class,
            "<init>","()V");
    if (construction_id == 0) {
        return -1;
    }
    mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class,
            construction_id);
    if (mTestProvider == NULL) {
        return -2;
    }
    return 1;
}
/**
 * 獲取時間 ---- 調用 Java 方法
 */
void GetTime() {
    if(TestProvider == NULL || getTime == NULL) {
        int result = InitProvider();
        if (result != 1) {
            return;
        }
    }
    jstring jstr = NULL;
    char* cstr = NULL;
    __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 方法
 */
void SayHello() {
    if(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) {
        int result = InitProvider() ;
        if(result != 1) {
            return;
        }
    }
    jstring jstrMSG = NULL;
    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    

#include <string.h>
#include <android/log.h>
#include <jni.h>
#include "Provider.h"
 
JNIEnv* jniEnv;
 
/**
 *  Java 中 聲明的native getTime 方法的實現
 */
void Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz)
{
 
    if(jniEnv == NULL) {
        jniEnv = env;
    }
 
    GetTime();
}
 
/**
 *  Java 中 聲明的native sayHello 方法的實現
 */
void Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz)
{
    if (jniEnv == NULL) {
        jniEnv = env;
    }
 
    SayHello();
}


3、運行效果

1、點擊 C調用java靜態方法」按鈕

 

C成功調用了Java中的getTime 方法,經過C方法打印出上層調用獲得的時間,而且上層成功吐司出調用信息出來。


 



2
、點擊 C調用java非靜態方法」按鈕

 

C成功調用了sayHello 方法併成功接收到 C 傳遞的參數,和 吐司出相對應的信息

 



 

4C調用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

相關文章
相關標籤/搜索