您的位置:首页 > 移动开发 > Android开发

基于 Android NDK 的学习之旅----- C调用Java(附源码)

2016-01-12 20:31 537 查看
许多成熟的C引擎要移植到Android平台上使用,一般都会提供一些接口,让Androidsdk和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中定义映射的类、方法、对象

jclassTestProvider;

jobjectmTestProvider;

jmethodIDgetTime;

jmethodIDsayHello;

C中映射类

TestProvider=(*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");

C中新建对象

jmethodIDconstruction_id=(*jniEnv)->GetMethodID(jniEnv,TestProvider,"<init>","()V");

TestProvidermTestProvider=(*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的两个方法

package
com.duicky;


/**

*

*

*@authorluxiaofeng<454162034@qq.com>

*

*/

public
class
TestProvider
{


public
static
String
getTime(){

LogUtils.printWithSystemOut(
"CallFromCJavaStaticMethod"
);

LogUtils.toastMessage(MainActivity.mContext,
"CallFromCJavaStaticMethod"
);

return
String.valueOf(System.currentTimeMillis());

}


public
void
sayHello(String
msg){

LogUtils.printWithSystemOut(
"CallFromCJavaNotStaticMethod:"
+
msg);

LogUtils.toastMessage(MainActivity.mContext,
"CallFromCJavaNotStaticMethod:"
+msg);

}


}


4、Android.mk文件关键代码

LOCAL_PATH:=$(callmy-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文件简介

5、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;


jclassTestProvider;

jobjectmTestProvider;

jmethodIDgetTime;

jmethodIDsayHello;


int
GetProviderInstance(jclassobj_class);


/**

*初始化类、对象、方法

*/

int
InitProvider(){


__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProviderBegin1"
);


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"
,
"InitProviderBegin2ok"
);

}


if
(mTestProvider==NULL){

if
(GetProviderInstance(TestProvider)
!=1){

(*jniEnv)->DeleteLocalRef(jniEnv,TestProvider);

return
-1;

}

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProviderBegin3ok"
);

}


if
(getTime==NULL){

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

if
(getTime==NULL){

(*jniEnv)->DeleteLocalRef(jniEnv,TestProvider);

(*jniEnv)->DeleteLocalRef(jniEnv,mTestProvider);

return
-2;

}

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProviderBegin4ok"
);

}


if
(sayHello==NULL){

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

if
(sayHello==NULL){

(*jniEnv)->DeleteLocalRef(jniEnv,TestProvider);

(*jniEnv)->DeleteLocalRef(jniEnv,mTestProvider);

(*jniEnv)->DeleteLocalRef(jniEnv,getTime);

return
-3;

}

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProviderBegin5ok"
);

}


__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"InitProviderBegin6"
);

return
1;


}


int
GetProviderInstance(jclassobj_class){


if
(obj_class==NULL){

return
0;

}


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

}

}


jstringjstr=NULL;

char
*cstr=NULL;

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"GetTimeBegin"
);

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

cstr=(
char
*)(*jniEnv)->GetStringUTFChars(jniEnv,jstr,0);

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"SuccessGetTimefromJava,Value=%s"
,cstr);

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"GetTimeEnd"
);


(*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
;

}

}


jstringjstrMSG=NULL;

jstrMSG=(*jniEnv)->NewStringUTF(jniEnv,
"Hi,I'mFromC"
);

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"SayHelloBegin"
);

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

__android_log_print(ANDROID_LOG_INFO,
"JNIMsg"
,
"SayHelloEnd"
);


(*jniEnv)->DeleteLocalRef(jniEnv,jstrMSG);

}


CToJava.c

#include<string.h>

#include<android/log.h>

#include<jni.h>

#include"Provider.h"


JNIEnv*jniEnv;


/**

*Java中声明的nativegetTime方法的实现

*/

void
Java_com_duicky_MainActivity_getTime(JNIEnv*env,jobjectthiz)

{


if
(jniEnv==NULL){

jniEnv=env;

}


GetTime();

}


/**

*Java中声明的nativesayHello方法的实现

*/

void
Java_com_duicky_MainActivity_sayHello(JNIEnv*env,jobjectthiz)

{

if
(jniEnv==NULL){

jniEnv=env;

}


SayHello();

}


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博客,转载请注明出处/article/5095940.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: