Android中关于JNI 的学习(5)在C文件中使用LogCat
Android中关于JNI 的学习(五)在C文件中使用LogCat
当程序在手机上运行的时候,我们就可以在LogCat中看到以下的记录:
在这里,我们会引用android/log.h头文件,而log.h头文件定义了几个log函数,如下:
2)引入log.h头文件之后,我们可以在C/C++中直接使用__android_log_print方法,不过老这样使用,就太麻烦了,所以我们可以重新定义一下,如下:
3)接下来,就是如何使用LOGI或者LOGD了,如下,在程序中需要写入log的地方,调用函数:
4)到这一步,在C/C++中的使用就结束了,但是JNI的使用一般都是通过编译成共享库的形式,所以我们还需要在Android.mk文件中指定对应的库文件,如下:
其中,我们可以看到 LOCAL_LDLIBS += -llog,在这里,LOCAL_LDLIBS 是告诉编译器,在编译这个共享库的时候,我们要去链接系统库中某一个库,而-llog,其实就是代表
Log是开发过程中,对于我们调试程序非常重要的一个工具,有很多时候,我们正是通过Log才能够看清楚程序是不是真的按照我们想像中的模式在跑,从而定位到问题所在的地方。而在Android开发中,毫无疑问,要是没有了logcat,我们调试程序的时候,就会痛苦死。
在NDK的开发中,尽管我们是利用C/C++来开发程序的,然后通过加载共享库的方法来调用C/C++程序,Android也提供了一套方法,可以让我们在LogCat中看到在C/C++代码中的数据流向,帮我们定位问题。
这一篇文章就简单地来说一下,如何在JNI层使用log工具。
回到我们之前的demo中,我们在程序中为了查看在JNI层某个数的值是否被改变了,我们特意添加了以下的log:
LOGI("before change testval = %d", val); val = val + 1; LOGI("after change testval = %d", val);
当程序在手机上运行的时候,我们就可以在LogCat中看到以下的记录:
这说明了,在C/C++中同样是可以利用log工具来调试的(其实这是废话,因为Android中Log的实现本来就是通过JNI层,由C++实现的。)
下面我们就来说一下,如何在C/C++文件中添加log吧。
1)在C/C++文件中,要添加log的引用文件,如下面第2行:
#include "com_lms_jni_ParamTransferTest.h" #include <android/log.h> #include <jni.h>
在这里,我们会引用android/log.h头文件,而log.h头文件定义了几个log函数,如下:
/* * Send a simple string to the log. */ int __android_log_write(int prio, const char *tag, const char *text); /* * Send a formatted string to the log, used like printf(fmt,...) */ int __android_log_print(int prio, const char *tag, const char *fmt, ...) #if defined(__GNUC__) __attribute__ ((format(printf, 3, 4))) #endif ; /* * A variant of __android_log_print() that takes a va_list to list * additional parameters. */ int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
2)引入log.h头文件之后,我们可以在C/C++中直接使用__android_log_print方法,不过老这样使用,就太麻烦了,所以我们可以重新定义一下,如下:
#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__)在这里,我们定义了LOGD和LOGI 可变参数宏,分别对应不同级别的__andoid_log_print函数,这样我们在代码中,就可以直接通过LOGD和LOGI来写入log信息了。
在log.h头文件中,我们可以查到LOG对应的级别信息,如下:
typedef enum android_LogPriority { ANDROID_LOG_UNKNOWN = 0, ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ } android_LogPriority;
3)接下来,就是如何使用LOGI或者LOGD了,如下,在程序中需要写入log的地方,调用函数:
JNIEXPORT void JNICALL Java_com_lms_jni_ParamTransferTest_changeTestVal (JNIEnv * env, jobject obj){ jclass clazz = (*env)->GetObjectClass(env,obj); jint val = (*env)->GetStaticIntField(env, clazz, (*env)->GetStaticFieldID(env, clazz,"testval","I")); LOGI("before change testval = %d", val); val = val + 1; LOGI("after change testval = %d", val); (*env)->SetStaticIntField(env, clazz,(*env)->GetStaticFieldID(env, clazz,"testval","I"),val); }
4)到这一步,在C/C++中的使用就结束了,但是JNI的使用一般都是通过编译成共享库的形式,所以我们还需要在Android.mk文件中指定对应的库文件,如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := com_lms_jni_HwDemo LOCAL_SRC_FILES := \ HwDemo.c \ JniTest.c \ ParamTransferTest.c LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)
其中,我们可以看到 LOCAL_LDLIBS += -llog,在这里,LOCAL_LDLIBS 是告诉编译器,在编译这个共享库的时候,我们要去链接系统库中某一个库,而-llog,其实就是代表
liblog库的意思,-l是表明lib,而log则是表明前缀是lib的liblog的库,跟LOCAL_MODULE一样,编译器和链接器会自动处理前缀lib跟后缀.so,而liblog.so这个库就是在ndk提供的系统库中,如下:
5)通过这几步,我们就可以像在Android调试一样,在C/C++中去调试我们的程序了。
结束。