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

前面一篇文章没有吧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方法生成这个对象;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值