Android NDK 开发入门详解(三) ---- Java和C++方法相互调用

一、Java调用C++方法

NdkTools.java :

package com.suhang.testdemo;

public class NdkTools {

    static {
        System.loadLibrary("native-lib");
    }
    //native 表示该方法为 C++ 方法
    public static native void sayHello();
}
  1. 先使用静态方法load library
  2. 在方法上按Alt+Enter,自动生成 C++ 方法代码
extern "C"
JNIEXPORT void JNICALL
Java_com_suhang_testdemo_NdkTools_sayHello(JNIEnv *env, jclass clazz) {
    // TODO: implement sayHello()
    LOGI("测试代码");
}

方法命名规则:

  1. JNIEXPORT void JNICALL : void 为返回值类型,其余两个为固定写法
  2. Java : 代表是Java方法
  3. com_suhang_testdemo : 包名
  4. NdkTools : 类名
  5. sayHello : 方法名

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

		NdkTools.sayHello();
    }
}

执行结果:

2021-10-20 16:12:22.000 12780-12780/com.suhang.testdemo I/suhang: 测试代码

二、C++调用Java方法

2.1 静态方法

2.1.1 C++调用Java静态方法

Ndktools.java

public class NdkTools {
    private static final String TAG = NdkTools.class.getSimpleName();

    static {
        System.loadLibrary("native-lib");
    }

    // C++ 方法,让两个数字相加
    public static native int add(int i1, int i2);

    // Java 方法,在C++方法内部调用该方法。当计算结束后,调用此方法。
    public static int result(int result) {
        Log.d(TAG, "result: " + result);
        return result;
    }
}

native-lib.cpp

extern "C"
JNIEXPORT jint JNICALL
Java_com_suhang_testdemo_NdkTools_add(JNIEnv *env, jclass clazz, jint i1, jint i2) {
    // TODO: implement add()

    // 1. 获取对应类
    //此处传入完整的包名及类型。使用"/"代替"."
    jclass cls = env->FindClass("com/suhang/testdemo/NdkTools");
    // 非空判断
    if (cls == NULL) { return -1; }
    
    // 2. 获取对应方法
    //第一个参数为方法所在类,第二个参数为方法名称,第三个参数为方法签名
    jmethodID method = env->GetStaticMethodID(cls, "result", "(I)I");
    // 非空判断
    if (method == NULL) { return -1; }

    // 3. 调用该方法
    env->CallStaticIntMethod(cls, method, i1 + i2);

    return i1 + i2;
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int add = NdkTools.add(2, 3);
        Log.d(TAG, "result is : " + add);
    }
}

调用结果:

2021-10-20 16:37:17.306 13107-13107/com.suhang.testdemo D/NdkTools: result: 5
2021-10-20 16:37:17.307 13107-13107/com.suhang.testdemo D/MainActivity: result is : 5

2.1.2 修改静态变量

与调用静态方法基本一致,只贴部分代码:
native-lib.cpp:

    //获取目标变量
    //第一个参数:类,第二个参数:变量名称,第三个参数:变量类型
    jfieldID fld_name = env->GetStaticFieldID(cls_tools, "name", "Ljava/lang/String;");
    if (fld_name == NULL) {
        return;
    }

    //设置目标变量
    jstring newName = env->NewStringUTF("francis");
    env->SetStaticObjectField(cls_tools, fld_name, newName);

2.2 C++调用实例方法:

调用实例方法与调用静态方法基本无异,只多出两个步骤。

  1. 实现方法类的构造方法
  2. 通过构造方法,实例出方法类

NdkTools.java:

public class NdkTools {
    private static final String TAG = NdkTools.class.getSimpleName();

    static {
        System.loadLibrary("native-lib");
    }
    
    public static native void message();

    public void message(String s){
        Log.d(TAG, "message: "+s);
    }
}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_suhang_testdemo_NdkTools_message(JNIEnv *env, jclass clazz) {
    // TODO: implement message()

    // 1. 获取对应类
    //此处传入完整的包名及类型。使用"/"代替"."
    jclass cls = env->FindClass("com/suhang/testdemo/NdkTools");
    // 非空判断
    if (cls == NULL) { return; }

    // 2. 获取对应方法
    //第一个参数为方法所在类,第二个参数为方法名称,第三个参数为方法签名
    jmethodID method = env->GetMethodID(cls, "message", "(Ljava/lang/String;)V");
    // 非空判断
    if (method == NULL) { return; }

    //******************************************************************************************
    //******************************************************************************************

    // 3. 找到构造方法
    // C++ 无法直接new出一个类来,所以需要实现一个类的构造方法,用来完成创建类的工作。
    // 构造方法名称为"<init>"
    jmethodID mtd_construct = env->GetMethodID(cls, "<init>", "()V");
    // 非空判断
    if (mtd_construct == NULL) { return; }

    // 4. 实例类
    jobject tools = env->NewObject(cls, mtd_construct, NULL);
    // 非空判断
    if (tools == NULL) {
        return;
    }

    //******************************************************************************************
    //******************************************************************************************

    // 5. 执行方法
    jstring test_message = env->NewStringUTF("测试 message");    //测试数据
    env->CallVoidMethod(tools, method, test_message);

    // 6. 删除引用
    env->DeleteLocalRef(cls);
    env->DeleteLocalRef(tools);
    env->DeleteLocalRef(test_message);
}

执行结果:

2021-10-20 16:57:07.351 13392-13392/com.suhang.testdemo D/NdkTools: message: 测试 message

2.2.2 修改实例变量

与修改静态变量基本一致,不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值