前面一篇文章没有吧jni的问题啰嗦完,所以,接着啰嗦……
上面提到c代码里获取java方法的参数里有 方法签名
下面讲下如何获取这个签名:
还是以前面的例子为基础打开studio下面的终端(Terminal),输入命令:
cd app\build\intermediates\classes\debug
命令好长记不住怎么办?每层目录只打前两个字母,按Tab键,你就看到效果了!
接着执行 javap命令:
javap -p -s com.game.my.jnigongcheng.MainActivity
参数-p -s 后面是要查看的类名全称。
结果如下:
Compiled from "MainActivity.java"
public class com.game.my.jnigongcheng.MainActivity extends android.support.v7.app.AppCompatActivity {
public com.game.my.jnigongcheng.MainActivity();
descriptor: ()V
protected void onCreate(android.os.Bundle);
descriptor: (Landroid/os/Bundle;)V
public native void say();
descriptor: ()V
public void toast();
descriptor: ()V
static {};
descriptor: ()V
}
其中,descriptor:后面就是方法签名了!
下面我们动手添加个方法:
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("hello");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
say();
}
public native void say();
public void toast(){
Toast.makeText(this, "java from C", Toast.LENGTH_SHORT).show();
}
public void toast(String str){
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
}
后面增加个toast的重载方法,只是多个参数。
获取方法签名之前,一定要点下锤子。
得到的签名为:(Ljava/lang/String;)V
下面,改动下c代码,调用这个方法:
//
// Created by my on 2016/10/20.
//
#include "com_game_my_jnigongcheng_MainActivity.h"
JNIEXPORT void JNICALL Java_com_game_my_jnigongcheng_MainActivity_say
(JNIEnv *env, jobject obj){
//先找到类
jclass jcla = (*env)->FindClass(env,"com/game/my/jnigongcheng/MainActivity");
if(jcla == 0){
//没找到类,直接返回
return;
}
//再找方法 注意:这里方法签名变了
jmethodID mid = (*env)->GetMethodID(env,jcla,"toast","(Ljava/lang/String;)V");
if(mid ==0){
//不解释
return;
}
//执行方法 这里传入了参数
(*env)->CallVoidMethod(env,obj,mid,(*env)->NewStringUTF(env,"这个吐司是C弹的!"));
}
点下锤子,运行,看到结果了吧!
这是在声明native方法所在类的方法调用,那么问题来了,别的类的方法能调用么?
当然可以了,要不然,我也不会在这里啰嗦了.
下面,新建个java类:
package com.game.my.jnigongcheng;
/**
* Created by my on 2016/10/20.
*/
public class Out {
public String hello(String name){
return "Hello!!"+name;
}
}
很简单的一个类,里面只有一个方法.
下面,获取方法签名,注意分号((Ljava/lang/String;)Ljava/lang/String;),修改c代码:
//
// Created by my on 2016/10/20.
//
#include "com_game_my_jnigongcheng_MainActivity.h"
JNIEXPORT void JNICALL Java_com_game_my_jnigongcheng_MainActivity_say
(JNIEnv *env, jobject obj){
//先找到类
jclass jcla = (*env)->FindClass(env,"com/game/my/jnigongcheng/Out");
jclass jclas = (*env)->FindClass(env,"com/game/my/jnigongcheng/MainActivity");
if(jcla == 0){
//没找到类,直接返回
return;
}
//再找方法
jmethodID mid = (*env)->GetMethodID(env,jcla,"hello","(Ljava/lang/String;)Ljava/lang/String;");
jmethodID method = (*env)->GetMethodID(env,jclas,"toast","(Ljava/lang/String;)V");
if(mid == 0 || method == 0){
//不解释
return;
}
//生成对象
jobject jobj = (*env)->AllocObject(env,jcla);
//执行方法
jstring jstr = (*env)->CallObjectMethod(env,jobj,mid,(*env)->NewStringUTF(env,"小明"));
(*env)->CallVoidMethod(env,obj,method,jstr);
}
可以看到,我们调用了Out的hello方法,生成一个字符串,然后又调用了MainActivity的toast方法
好了,现在总结下C语言调用java的方法:
1. 通过(*env)->FindClass方法找到class对象;
2.根据class对象找到他的方法;
3.利用对象执行方法,如果是本类,就是传入的jobject对象,如果是其他类,就需要(*env)->AllocObject方法生成这个对象;