4个案例速学JNI(C 函数 调用 Java 代码,附完整项目)

整个Demo下载

https://github.com/linweimao/NDK-C-Java-

C回调Java方法的核心思想

  1. C回调Java方法的核心思想: 反射

得到一个方法的签名

  1. 如何得到一个方法的签名?

    执行命令: javap -s 全类名, 显示所有方法的签名信息

    在执行命令之前最好编译一下,这样才有 class 文件(编译的意思就是Build(Rebuild Project)一下)
    在这里插入图片描述
    先进入到要生成方法签名的类的目录下

在输入命令

javap -s JNITest.class
//或者
javap -s JNITest

这个是输入javap -s JNITest.class在这里插入图片描述
这个是输入javap -s JNITest
在这里插入图片描述

生成头文件的方式

点击 Terminal 输入命令,便可以生成一个JNI的 C 头文件.

输入第二个命令行提示错误的原因是注释为中文。所以在输入命令行时不能出现注释或者中文
在这里插入图片描述

javac  -h  ./  JNI.java

上面的命令的作用:根据Java中的 native 方法生成对应在 C 中的方法该怎么写(自动生成)

在这里插入图片描述
()V就为方法签名
在这里插入图片描述
cd进去到 JNITest 的根目录下 输入命令查看方法签名 :javap -s JNITest
在这里插入图片描述
在这里插入图片描述

C回调Java方法

测试1: 回调一般方法(无参无返回)

Java端 native
public native void callbackHelloFromJava();
C端函数
/*

测试1: 回调一般方法(无参无返回)

//1. 加载类得到jclass对象:

    //jclass (*FindClass)(JNIEnv*, const char*);

//2. 得到对应方法的Method对象 : GetMethodId()

    //jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*)

//3. 创建类对象

   //jobject (*AllocObject)(JNIEnv*, jclass);

//4. 调用方法(无返回值)

  //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...)

*/

void Java_com_atguigu_ccalljava_JNI_callbackHelloFromJava

  (JNIEnv * env, jobject obj) {



	//1. 加载类得到jclass对象:

		//jclass      (*FindClass)(JNIEnv*, const char*);

	jclass jc = (*env)->FindClass(env, "com/atguigu/ccalljava/JNI");

	//2. 得到对应方法的Method对象 : GetMethodId()

		//jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*)

	jmethodID method = (*env)->GetMethodID(env, jc, "helloFromJava", "()V");

	//3. 创建类对象

		//jobject     (*AllocObject)(JNIEnv*, jclass);

	jobject obj2 = (*env)->AllocObject(env, jc);

	//4. 调用方法

	(*env)->CallVoidMethod(env, obj2, method);

}
java端被回调方法
public void helloFromJava() {

		Log.e("TAG", "helloFromJava()");

}

测试2: 回调带int参数方法

Java端 native
public native void callbackAdd();
C端函数
/*

测试2: 回调带int参数方法

//1. 加载类得到jclass对象:

//2. 得到对应方法的Method对象 : 

//3. 创建类对象

//4. 调用方法(无返回值)

  //jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...)

*/

void JNICALL Java_com_atguigu_ccalljava_JNI_callbackAdd

  (JNIEnv * env, jobject obj) {



	//1. 加载类得到class对象

	jclass jc = (*env)->FindClass(env, "com/atguigu/ccalljava/JNI");

	//2. 得到对应方法的Method对象

	jmethodID method = (*env)->GetMethodID(env, jc, "add", "(II)I");

	//3. 创建类对象

	jobject obj2 = (*env)->AllocObject(env, jc);

	//4. 调用方法

	(*env)->CallIntMethod(env, obj2, method, 3, 4);

}
java端被回调方法
public int add(int x, int y) {

		Log.e("TAG","add() x=" + x+" y="+y);

		return x + y;

}

测试3: 回调带String参数方法

Java端 native
public native void callbackPrintString();
C端函数
/*

测试3: 回调带String参数方法

//1. 加载类得到jclass对象:

//2. 得到对应方法的Method对象 : 

//3. 创建类对象

//4. 调用方法(带String参数的无返回值)

  //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...)

*/

void Java_com_atguigu_ccalljava_JNI_callbackPrintString

  (JNIEnv * env, jobject obj) {

	//1. 加载类得到class对象

	jclass jc = (*env)->FindClass(env, "com/atguigu/ccalljava/JNI");

	//2. 得到对应方法的Method对象

	jmethodID method = (*env)->GetMethodID(env, jc, "printString", "(Ljava/lang/String;)V");

	//3. 创建类对象

	jobject obj2 = (*env)->AllocObject(env, jc);

	//4. 调用方法

	jstring js = (*env)->NewStringUTF(env, "I from C");

	(*env)->CallVoidMethod(env, obj2, method, js);

}
java端被回调方法
public void printString(String s) {

		Log.e("TAG","C中输入的:" + s);
}

测试4: 回调静态方法

Java端 native
public native void callbackSayHello();
C端函数
/*

测试4: 回调静态方法

//1. 加载类得到jclass对象:

//2. 得到对应方法的Method对象 : 

	//jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*)

//3. 调用方法

	//void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...)

*/

void Java_com_atguigu_ccalljava_JNI_callbackSayHello

  (JNIEnv * env, jobject obj) {

	//1. 加载类得到class对象

	jclass jc = (*env)->FindClass(env, "com/atguigu/ccalljava/JNI");

	//2. 得到对应方法的Method对象

	jmethodID method = (*env)->GetStaticMethodID(env, jc, "sayHello", "(Ljava/lang/String;)V");

	//3. 调用方法

	jstring js = (*env)->NewStringUTF(env, "I from C");

	(*env)->CallStaticVoidMethod(env, jc, method, js);

}
java端被回调方法
public static void sayHello(String s){

		Log.e("TAG",  "我是java代码中的JNI."

				+ "java中的sayHello(String s)静态方法,我被C调用了:"+ s);

}

JNI层日志打印

在这里插入图片描述
其实就是靠这个(liblog.so)so库打印日志

  1. 配置 jni 文件下的 Android.mk文件 输入 LOCAL_LDLIBS := -llog 打印日志库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog

LOCAL_MODULE := ccalljava

LOCAL_SRC_FILES := CCallJava.c

include $(BUILD_SHARED_LIBRARY)

在这里插入图片描述
2. 在代码中要打印日志就要定义出来
在这里插入图片描述

3. 包含日志头文件, 定义日志输出函数

	#include <android/log.h>

	#define LOG_TAG "atlinweimao"

	#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

	#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

	#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

调用 __android_log_print 这个方法打印日志

__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS)

第一个参数为日志的等级,
第二个参数为 TAG:标志
第三个参数为__VA_ARGS__:可变参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值