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

JNI 在Android中的详细用法(续集)

2016-10-20 16:41 369 查看
前面一篇文章没有吧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方法生成这个对象;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息