本文将带你了解Android应用开发Android JNI-c/c++调用java方法,希望本文对大家学Android有所帮助。
"
Android JNI-c/c++调用java方法,在使用ndk开发的时候,java调用c/c++方法是必须要的。但是很多时候,c/c++有callback需要反馈给java的时候(比如IM通讯登录成功信息和一些异常信息),就需要c/c++调用java方法了。
在看这篇文章之前,必须对JNI有一些基础的了解,比如java调用c/c++方法,java和c/c++ jni在一些基本类型上的对应(int对应jint等)。
那么现在介绍一下c/c++调用java方法的基本步骤:
1.需要把java方法所在类的实例通过JNI方法传到c/c++
java:JNI, 这是c需要回调的java方法,然后通过调用自身init()方法,把java实例传到c层
?
1
2
3
4
5
6
class JNI {
public native void init(JNI obj);
public void error(int code) {
Log.i(""JNI"", ""c++ call error "");
}
}
c:这里把java传递进来的objListener,保存到c的jniobj结构体内。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
JNIEXPORT jint JNICALL Java_com_arcvideo_rtcmessage_JNI_init(
JNIEnv *env,
jobject oj,
jobject objListener,
)
{
if(objListener == MNull){
MVLOG(""objListener is null"");
}else
{
MVLOG(""get java obj"");
jniobj->g_obj = env->NewGlobalRef(objListener);
}
return res;
}
typedef struct _tagJNIObj{//这个是刚才保存java实例的结构体,在还有其他参数
jmethodID JNI_error;
JavaVM* g_jvm;
JNIEnv* g_ThreadEnv;
jclass g_class;
jobject g_obj;
MHandle g_h;
}JNIObj;
static JNIObj* jniobj = MNull;
2.在c层拿到java class
c:通过jni提供的FindClass方法和完整类名,可以拿到class引用
?
1
2
static const char* const DL_CLASS_NAME = ""com/arcvideo/rtcmessage/JNI"";
jniobj->g_class = env->FindClass(DL_CLASS_NAME);
3.在c层拿到java method
c:根据刚才拿到的java class引用有jni提供的GetMethodID方法,和方法名,入参,就可以拿到method引用
?
1
2
3
4
5
6
// error
jniobj->JNI_error = env->GetMethodID(jniobj->g_class, ""error"",
""(I)V"");
if(jniobj->JNI_error == MNull){
MVLOG(""create JNI_error is error"");
}
4.调用method
c:在需要调用的地方调用这个java方法,
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static void error(MDWord code, MVoid* pObj)
{
MVLOG(""RtcMessageJNI error is in code : %d"", code );
if(jniobj->g_ThreadEnv == MNull)
{
MVLOG(""attach current thread start"");
jniobj->g_jvm -> AttachCurrentThread(&jniobj->g_ThreadEnv, MNull);
if(jniobj->g_ThreadEnv == MNull){
MVLOG(""attach current thread is error"");
return;
}
}
if(jniobj && jniobj->JNI_error){
MVLOG(""RtcMessageJNI error is called"");
//这里是最关键的调用过程,通过JNI提供的CallVoidMethod,来调用,加入参数,class引用,method应用,已经入参,这样调用java方法就完成了。
jniobj->g_ThreadEnv->CallVoidMethod(jniobj->g_obj, jniobj->JNI_error,
(int)code);
}
if(jniobj->g_jvm){
MVLOG(""RtcMessageJNI error method detach"");
jniobj->g_jvm->DetachCurrentThread();
jniobj->g_ThreadEnv = MNull;
}
}
这里在调用java方法的时候调用了,AttachCurrentThread和DetachCurrentThread方法,这是必须的,如果不调用AttachCurrentThread就拿不到线程的引用,会报错误。然后在调用结束的时候要调用DetachCurrentThread,也就是释放线程。根据个人经验,最好每次调用java方法结束的时候都调用DetachCurrentThread,这样基本不会出错。
"
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!