上一篇介绍了 java调用c方法返回值,今天总结下c调用java。
大体说下步骤,第一步是 找到class,第二步找到方法,第三步是env指针 进行调用。类似于反射。 下面详细说一下。
- 书写java本地代码,调用c方法,并且书写提供给c语言调用的java方法。这里多写几个
public class NativeMethods {
Context context;
// 加载ku
static {
System.loadLibrary("callback");
}
public NativeMethods(Context context) {
this.context = context;
}
//调用c语言 无参无返回
public native void callBack();
//调用c语言 物参有返回
public native String callBackReturnString();
//调用c语言 有参数又返回值
public native String callBackWithParmString();
//c的 callBack函数 回调java的方法(无参无返回)
public void callBackFromC() {
Toast.makeText(context, "c调用了java", Toast.LENGTH_SHORT).show();
}
//c的 callBackReturnString函数 回调java的方法(无参返回string)
public String callBackFromCString() {
return "来自java的字符串";
}
//c语言 callBackWithParmString回调 有参数又返回值
public int add(int a, int b) {
return a + b;
}
//c回调的静态方法
public static String callBackStatic() {
return "java的静态方法";
}
//调用c方法,c方法回调静态方法。
public native String callStaticFromc();
}
2.接下来就是生成头文件了,在model目录下的 src/main/java目录下,执行javah
javah -d ../jni com.example.callbcakdemo.NativeMethods
这样就在java的上层也就是main下面自动生成了jni目录和头文件,下面就是写c代码了
3. c调用java的非静态 方法。
首先是我们要用java调用c,然后在c里面回调我们的java方法。,这里先说非静态的方法
步骤分下面几步
a.得到类的class
b.得到方法id
c.调用方法
这三步都是env指针提供的方法。
首选来看下无参无返回的callBack方法
第一步得到class使用的env的findclass方法拿到jclass返回值
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
第一个参数是env指针,后面的是类的全名
这里可以用log判断下是否拿到了class
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
¥##################################################################
第二步查找方法id,找到方法。
查找方法使用的env的GetMethodID方法(对于非静态的方法,如果是静态方法使用GetstaticMethodID)
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
GetMethodID方法接受四个参数,第一个是env指针,第二个刚才第一步找到jclass,第三个是你要调用的方法名称,第四个参数是你要调用的方法签名。 签名这里注意,需要使用javap方法来生成签名。
javap是对class进行类似反编译拿到参数列表。进入到studio的class目录,是在build下面的intermediates/classes/目录。。
然后进入回调方法所在的包,这里和native写在一个文件里面。
cd build/intermediates/classes/debug/com/example/callbcakdemo/
然后执行javap 要参数-s -p
javap -s -p NativeMethods.class
然后看下输出结果
public class com.example.callbcakdemo.NativeMethods {
android.content.Context context;
descriptor: Landroid/content/Context;
public com.example.callbcakdemo.NativeMethods(android.content.Context);
descriptor: (Landroid/content/Context;)V
public native void callBack();
descriptor: ()V
public native java.lang.String callBackReturnString();
descriptor: ()Ljava/lang/String;
public native java.lang.String callBackWithParmString();
descriptor: ()Ljava/lang/String;
public void callBackFromC();
descriptor: ()V
public java.lang.String callBackFromCString();
descriptor: ()Ljava/lang/String;
public int add(int, int);
descriptor: (II)I
static {};
descriptor: ()V
}
每个方法都descriptor,后面的就是env getmethodid需要的第四个参数,仔细看看不难发现规律
这样我们就可以得到方法的id,对于非静态的方法这样获取id。各个方法的签名不同
//无参无返回的方法,
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "callBackFromC", "()V");
//物参数返回string
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "callBackFromCString",
"()Ljava/lang/String;");
//接受2int,返回一个int
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "add",
"(II)I");
这样就能拿到方法id了进行调用了。
¥#################################################################
第三步进行调用
调用java方法根据方法的签名和返回值不同而不同。 调用方法是(env)->callMethod,type是返回值的类型。方法参数列表一般为(JNIEnv, jobject, jmethodID, …)。第一个是env,第二个是object的一个实例,就是c方法第二个参数jobject,这里用上了,第三个是方法的id,就是刚才找到的,后面是一个可变参数,有几个就写几个就行了。
//调用无参无返回的。
(*env)->CallVoidMethod(env, obj, jmethod1);
//调用无参数 返回string
jstring res = (*env)->CallObjectMethod(env, obj, jmethod1);
//调用传入2个int,返回一个int的
jint res = (*env)->CallIntMethod(env, obj, jmethod1, 2, 5);
其中规律不难发现,打开jni.h都可以看到这些方法的定义,可以看到具体的类型。由于返回string没有cllstringmethod的方法,所以调用了object,返回用jstring接受下就可以了。
到这里就是c调用java的非静态方法,一会贴上全部代码
4。调用静态方法
第一步 找class是一样的,第二部,第三步不一样了。寻找方法id需要使用getstaticmethodid来找,调用的时候也要是用static来调用。看下例子。
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callStaticFromc
(JNIEnv *env, jobject obj)
{
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
jmethodID jmethod1 = (*env)->GetStaticMethodID(env, clazz, "callBackStatic",
"()Ljava/lang/String;");
if (jmethod1 == 0)
LOGE("methodid error");
else
LOGE("method ok");
jstring res = (*env)->CallStaticObjectMethod(env, clazz, jmethod1);
return res;
}
静态和非静态的区别需要注意调用的时候静态是用class,非静态是用实例。 ok。下面贴上源码
首先是定义nativie方法和 回调方法的类,
package com.example.callbcakdemo;
import android.content.Context;
import android.widget.Toast;
public class NativeMethods {
Context context;
// 加载ku
static {
System.loadLibrary("callback");
}
public NativeMethods(Context context) {
this.context = context;
}
//调用c语言 无参无返回
public native void callBack();
//调用c语言 物参有返回
public native String callBackReturnString();
//调用c语言 有参数又返回值
public native String callBackWithParmString();
//c的 callBack函数 回调java的方法(无参无返回)
public void callBackFromC() {
Toast.makeText(context, "c调用了java", Toast.LENGTH_SHORT).show();
}
//c的 callBackReturnString函数 回调java的方法(无参返回string)
public String callBackFromCString() {
return "来自java的字符串";
}
//c语言 callBackWithParmString回调 有参数又返回值
public int add(int a, int b) {
return a + b;
}
//c回调的静态方法
public static String callBackStatic() {
return "java的静态方法";
}
//调用c方法,c方法回调静态方法。
public native String callStaticFromc();
}
下面是生成h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef _Included_com_example_callbcakdemo_NativeMethods
#define _Included_com_example_callbcakdemo_NativeMethods
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_example_callbcakdemo_NativeMethods_callBack
(JNIEnv *, jobject);
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callBackReturnString
(JNIEnv *, jobject);
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callBackWithParmString
(JNIEnv *, jobject);
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callStaticFromc
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
.c文件
#include "com_example_callbcakdemo_NativeMethods.h"
#include <android/log.h>
#define TAG "callBack" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
//c 用java 没有返回值的调用
JNIEXPORT void JNICALL Java_com_example_callbcakdemo_NativeMethods_callBack
(JNIEnv *env, jclass obj)
{
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "callBackFromC", "()V");
if (jmethod1 == 0)
LOGE("methodid error");
else
LOGE("method ok");
(*env)->CallVoidMethod(env, obj, jmethod1);
}
//调用java 不带参数 返回string
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callBackReturnString
(JNIEnv *env, jobject obj)
{
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "callBackFromCString",
"()Ljava/lang/String;");
if (jmethod1 == 0)
LOGE("methodid error");
else
LOGE("method ok");
jstring res = (*env)->CallObjectMethod(env, obj, jmethod1);
return res;
}
//c调用java 出入参数,返回值
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callBackWithParmString
(JNIEnv *env, jobject obj)
{
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
jmethodID jmethod1 = (*env)->GetMethodID(env, clazz, "add",
"(II)I");
if (jmethod1 == 0)
LOGE("methodid error");
else
LOGE("method ok");
jint res = (*env)->CallIntMethod(env, obj, jmethod1, 2, 5);
char string[2];
string[0] = res + '0';
string[1] = '\0';
return (*env)->NewStringUTF(env, string);
}
//call back static
JNIEXPORT jstring JNICALL Java_com_example_callbcakdemo_NativeMethods_callStaticFromc
(JNIEnv *env, jobject obj)
{
jclass clazz = (*env)->FindClass(env, "com/example/callbcakdemo/NativeMethods");
if (clazz == 0)
LOGE("class is error ");
else
LOGE("class is ok");
jmethodID jmethod1 = (*env)->GetStaticMethodID(env, clazz, "callBackStatic",
"()Ljava/lang/String;");
if (jmethod1 == 0)
LOGE("methodid error");
else
LOGE("method ok");
jstring res = (*env)->CallStaticObjectMethod(env, clazz, jmethod1);
return res;
}
最后就是mainactivity的测试代码,这里就不说了,自己调用就行。
demo下载地址:http://download.csdn.net/detail/spinchao/9594550