实现目标:
- c对java调用的两种方式
- 实现静态方法和成员方法
- 跨线程完成调用
- 写一个方法发回调
c对java调用的两种方式
方式一是通过传递过去一个实体,方式二是不传递实体,而是通过类名来创建的。
方式一:传递一个实体过去。
传递了实体,我们需要通过实体找到class类,通过class类来获取类的方法,然后通过实体来调用方法。
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_JNIPeople(JNIEnv *env, jobject thiz, jobject people) {
// 需要获取方法,老方法 ,直接使用findclass 得到类class
jclass peclass = env->GetObjectClass(people);
// 下面的一样 得到方法名字
jmethodID setNam = env->GetMethodID(peclass,"setName", "(Ljava/lang/String;)V");
jmethodID getNam = env->GetMethodID(peclass,"getName", "()Ljava/lang/String;");
jmethodID setA = env->GetMethodID(peclass,"setAge", "(I)V");
jmethodID getA = env->GetMethodID(peclass,"getAge", "()I");
//调用方法
jstring xx = env->NewStringUTF("ddd");
env->CallVoidMethod(people,setA,0);
env->CallVoidMethod(people,setNam,xx);
jint cc = env->CallIntMethod(people,getA);
jobject names = env->CallObjectMethod(people,getNam);
//调用回调方法
jmethodID inisuc = env->GetMethodID(peclass,"initSuccess", "()V");
env->CallVoidMethod(people,inisuc);
}
方式二:类名创建
通过路径得到构造方法,通过构造方法创建实体。然后其他的和上面的一样。
/**
* 使用类名的方式
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_JNIPeopleFanshe(JNIEnv *env, jobject thiz) {
// 使用c++的方式创建字符串
std::string clazzName = "com/example/ccalljava/People";
// 得到class
jclass jscc = env->FindClass(clazzName.c_str());
// 得到构造方法
jmethodID initMa = env->GetMethodID(jscc,"<init>","()V");
// 根据构造 方法创建对象
jobject pInstance = env->NewObject(jscc,initMa);
//// 我们得到里面的方法
jmethodID psetName= env->GetMethodID(jscc,"setName","(Ljava/lang/String;)V");
jmethodID psetAge= env->GetMethodID(jscc,"setAge","(I)V");
//// 调用
env->CallVoidMethod(pInstance,psetAge,1);
jstring xx = env->NewStringUTF("ddd");
env->CallVoidMethod(pInstance,psetName, xx);
}
这两种方式的思路也是很简单的,
java方法
public class People {
private String name;
private int age;
public People(){
System.out.println("------------ 初始化");
}
public void setName(String name) {
System.out.println("------------ setName"+name);
this.name = name;
}
public void setAge(int age) {
System.out.println("------------ setAge"+age);
this.age = age;
}
public String getName() {
System.out.println("------------ getName"+name);
return name;
}
public int getAge() {
System.out.println("------------ getAge"+age);
return age;
}
public void initSuccess(){
System.out.println("------------ success");
listener.success();
}
private SuccessListener listener;
public void setListener(SuccessListener listener){
this.listener = listener;
}
interface SuccessListener{
public void success();
}
}
静态方法
native void staticDemo();
public static void testStatic(){
System.out.println("----静态方法!");
}
``
jni方法
```c++
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_staticDemo(JNIEnv *env, jobject thiz) {
jclass thizClass = env->GetObjectClass(thiz);
jmethodID xx = env->GetStaticMethodID(thizClass,"testStatic","()V");
env->CallStaticVoidMethod(thizClass,xx);
}
线程创建对象
案例没跑起来,原因不知道,反正就是在子线程中一直无法找到类,需要注意的是跨线程需要使用到vm和env,我们可以在加载的时候初始化
JNIEnv *encz;
JavaVM *vm1;
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){
vm1 = vm;
//获取JNI版本
vm->GetEnv((void**)&encz, JNI_VERSION_1_6);
return JNI_VERSION_1_6;
}
但是下面的就有点奇怪,就是跑不起来,一直找不到类
void* threadM(void *args){
// JNIEnv *env;
// vm1->GetEnv((void**)env, JNI_VERSION_1_6);
int xx = vm1->AttachCurrentThread(&encz, NULL);
// 使用c++的方式创建字符串
std::string clazzName = "com/example/ccalljava/People";
// 得到class
jclass jscc = encz->FindClass(clazzName.c_str());
// 得到构造方法
jmethodID initMa = encz->GetMethodID(jscc,"<init>","()V");
// 根据构造 方法创建对象
// jobject pInstance = env->NewObject(jscc,initMa);
////// 我们得到里面的方法
// jmethodID psetName= env->GetMethodID(jscc,"setName","(Ljava/lang/String;)V");
// jmethodID psetAge= env->GetMethodID(jscc,"setAge","(I)V");
////// 调用
// env->CallVoidMethod(pInstance,psetAge,1);
// jstring xx = env->NewStringUTF("ddd");
// env->CallVoidMethod(pInstance,psetName, xx);
// vm1->DetachCurrentThread();
return 0;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_threadDemo(JNIEnv *env, jobject thiz) {
pthread_t pid;
pthread_create(&pid, 0, threadM, 0);
}
使用实体跨线程创建
这个需要注意是,需要对传如的对象进行全局化操作。
void* three(void* args){
// 读取数据包
jobject people = static_cast<jobject>(args);
JNIEnv *jniEnv;
vm1->AttachCurrentThread(&jniEnv, NULL);
jclass jscc = jniEnv->GetObjectClass(people);
jmethodID xx = jniEnv->GetMethodID(jscc,"setAge","(I)V");
jniEnv->CallVoidMethod(people,xx,1);
return 0;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_threadDemoInstance(JNIEnv *env, jobject thiz,
jobject people) {
// env->GetJavaVM(&vm1);
pthread_t pid;
//这句话很重要 因为在另一个线程里,这个方法结束了就会将数据清除了
jobject p = env->NewGlobalRef(people);
pthread_create(&pid,0,three,p);
}
使用类名加载不知道什么不行。
网友评论