JNI学习笔记2-Java传给C-C代码中向logcat输出内容-C代码回调java方法

Posted lw-blog-666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI学习笔记2-Java传给C-C代码中向logcat输出内容-C代码回调java方法相关的知识,希望对你有一定的参考价值。

Java传递数据给C例子:

public class JNI {

static{
System.loadLibrary("passdata");
}

//传递两个int类型的变量给C 让C加一下返回来
public native int add(int x, int y);
//传递String类型的参数给C 处理一下返回来
public native String sayHelloInC(String s);
//传递int类型的数组给C
public native int[] arrElementsIncrease(int[] intArray);
}

C语言中编写:

 

#include <jni.h>
#include <stdlib.h>

#include <android/log.h>

#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT jint JNICALL Java_com_itheima_javapassdata_JNI_add
(JNIEnv * env, jobject clazz, jint x, jint y){
return x+y;
}

/**
* 把一个jstring转换成一个c语言的char* 类型.
*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}

JNIEXPORT jstring JNICALL Java_com_itheima_javapassdata_JNI_sayHelloInC
(JNIEnv * env, jobject clazz, jstring jstr){
//调用工具方法把 java中的string 类型 转换成 C 语言中的 char*
char* cstr = _JString2CStr(env,jstr);
//调用strlen 获取 cstr 字符串的长度
int length = strlen(cstr);
int i;
for(i = 0;i<length;i++){
*(cstr+i) += 1;
}
return (*env)->NewStringUTF(env,cstr);
}

 

JNIEXPORT jintArray JNICALL Java_com_itheima_javapassdata_JNI_arrElementsIncrease
(JNIEnv * env, jobject clazz, jintArray jArray){
//jsize (*GetArrayLength)(JNIEnv*, jarray);
jsize length =(*env)->GetArrayLength(env,jArray);
LOGD("length = %d",length);
//jboolean iscopy;
//jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
int* arrayPointer =(*env)->GetIntArrayElements(env,jArray,NULL);
int i;
for(i = 0;i<length;i++){
*(arrayPointer+i) += 10;
}
return jArray;
}

C代码中向logcat输出内容

Android.mk文件增加以下内容
LOCAL_LDLIBS += -llog
C代码中增加以下内容
#include <android/log.h>
#define LOG_TAG "System.out"
#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 C的宏定义 起别名 #define LOGTAG "System.out" 给"System.out"起别名LOGTAG
  • #define LOGI(...) androidlogprint(ANDROID_LOGINFO, LOGTAG, _VAARGS)
  • 给 androidlogprint函数起别名 写死了前两个参数 第一个参数 优先级 第二个参数TAG
  • VAARGS_ 可变参数的固定写法
  • LOGI(...)在调用的时候 用法跟printf()一样

C代码回调java方法(反射)

  • ① 找到字节码对象
    • //jclass (FindClass)(JNIEnv, const char*);
    • //第二个参数 要回调的java方法所在的类的路径 "com/itheima/callbackjava/JNI"
  • ② 通过字节码对象找到方法对象
    • //jmethodID (GetMethodID)(JNIEnv, jclass, const char, const char);
    • 第二个参数 字节码对象 第三个参数 要反射调用的java方法名 第四个参数 要反射调用的java方法签名
    • 获得方法签名:javap -s 要获取方法签名的类的全类名 项目/bin/classes 运行javap
  • ③ 通过字节码创建 java对象(可选) 如果本地方法和要回调的java方法在同一个类里可以直接用 jni传过来的java对象 调用创建的Method
    • jobject obj =(*env)->AllocObject(env,claz);
    • 当回调的方法跟本地方法不在一个类里 需要通过刚创建的字节码对象手动创建一个java对象
    • 再通过这个对象来回调java的方法
    • 需要注意的是 如果创建的是一个activity对象 回调的方法还包含上下文 这个方法行不通!!!回报空指针异常
  • ④ 反射调用java方法
    • //void (CallVoidMethod)(JNIEnv, jobject, jmethodID, ...);
    • 第二个参数 调用java方法的对象 第三个参数 要调用的jmethodID对象 可选的参数 调用方法时接收的参数

例子:

public class JNI {
static{
System.loadLibrary("callback");
}
private Context mContext;
public JNI(Context context){
mContext = context;
}
public native void callbackvoidmethod();

public native void callbackintmethod();

public native void callbackStringmethod();

public native void callbackShowToast();
//C调用java空方法
public void helloFromJava(){
System.out.println("hello from java");
}
//C调用java中的带两个int参数的方法
public int add(int x,int y) {
return x+y;
}
//C调用java中参数为string的方法
public void printString(String s){
System.out.println(s);
}
public void showToast(String s){
Toast.makeText(mContext, s, 0).show();
}
}

C文件中:

 

#include <jni.h>
#include <stdlib.h>
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
/**
* 把一个jstring转换成一个c语言的char* 类型.
*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}
JNIEXPORT void JNICALL Java_com_itheima_callbackjava_JNI_callbackvoidmethod
(JNIEnv * env, jobject clazz){
//jclass (*FindClass)(JNIEnv*, const char*);
//① 获取字节码对象
jclass claz = (*env)->FindClass(env,"com/itheima/callbackjava/JNI");
//②获取Method对象,第四个参数为方法签名
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID methodID =(*env)->GetMethodID(env,claz,"helloFromJava","()V");
//③通过字节码对象创建一个Object
//④通过对象调用方法
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,clazz,methodID);

}

JNIEXPORT void JNICALL Java_com_itheima_callbackjava_JNI_callbackintmethod
(JNIEnv * env, jobject clazz){
//① 获取字节码对象
jclass claz =(*env)->FindClass(env,"com/itheima/callbackjava/JNI");
//②获取Method对象
jmethodID methodID = (*env)->GetMethodID(env,claz,"add","(II)I");
//jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
int result =(*env)->CallIntMethod(env,clazz,methodID,3,4);
LOGD("result = %d",result);
}

JNIEXPORT void JNICALL Java_com_itheima_callbackjava_JNI_callbackStringmethod
(JNIEnv * env, jobject clazz){
//① 获取字节码对象
jclass claz =(*env)->FindClass(env,"com/itheima/callbackjava/JNI");
//② 获取Method对象
jmethodID methodid =(*env)->GetMethodID(env,claz,"printString","(Ljava/lang/String;)V");
//
jstring result =(*env)->NewStringUTF(env,"hello from c");
(*env)->CallVoidMethod(env,clazz,methodid,result);
}
JNIEXPORT void JNICALL Java_com_itheima_callbackjava_JNI_callbackShowToast
(JNIEnv * env, jobject clazz){
jclass claz =(*env)->FindClass(env,"com/itheima/callbackjava/JNI");
jmethodID methodid =(*env)->GetMethodID(env,claz,"showToast","(Ljava/lang/String;)V");
//jobject (*AllocObject)(JNIEnv*, jclass);
//通过字节码对象创建 java对象 在这儿就是创建了mainactivity的对象
//jobject obj =(*env)->AllocObject(env,claz);
jstring result =(*env)->NewStringUTF(env,"hello from c");
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,clazz,methodid,result);
}

























































































































































以上是关于JNI学习笔记2-Java传给C-C代码中向logcat输出内容-C代码回调java方法的主要内容,如果未能解决你的问题,请参考以下文章

JNI学习笔记

java jni 调用 c 代码, c 中 unsigned char* 数据 如何传给java?

Android JNI学习笔记-数据类型映射以及native调用java

JNI 学习笔记-- JNI访问数组引用异常处理缓存策略

Android JNI和NDK学习(09)--JNI实例二 传递类对象

如何把c++中的unsigned char* mData的数据指针通过jni把数据传给java使用?