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++中去调试我们的程序了。
结束。
分享到:
相关推荐
Android JNI Android JNI 用C函数写本地库读写文件,底层调用小例子用C函数写本地库读写文件,底层调用小例子
本示例实现了Android JNI在C语言中打印log的配置,有关本示例的详细解析请参考博文:http://blog.csdn.net/l1028386804/article/details/47425073
这是一个androidstudio环境下的jni的学习,里面包含了基本数据类型转化,引用数据类型转化,json格式数据类型的转化等
本程序是在Eclipse中创建的一个Android Application,该项目中是在JNI中利用OpenGL ES库和OpenCV库进行一副图片的渲染。
android_JNI学习五最后代码实例
Android中实现JNI的AES加解密源代码,绝对可以运行!
Android使用JNI调用Python so解释器
Android中调用JNI例子,对应博客http://blog.csdn.net/wwj_748/article/details/28300451
Android 通过JNI调用C语言完整示例程序。Android Studio项目工程。
android中jni的简单使用示例代码
Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块.pdfAndroid通过JNI实现与C语言的串口通讯操作蓝牙硬件模块.pdfAndroid通过JNI实现与C语言的串口通讯操作蓝牙硬件模块.pdfAndroid通过JNI实现与C语言的串口通讯...
android JNI学习三的最后代码实例
例子通过jni调用libzip库读取压缩文件,和通过ndk自带api接口读取assets资源文件,附测试工程。
android jni使用curl进行http请求和文件下载,具体说明参考博客 http://blog.csdn.net/csdn49532/article/details/50680716
将AES加密算法用C语言实现并封装成JNI接口供Android调用,包含编译生成的SO库文件,以及Java声明和调用方法的简单例子。希望帮到有需要的朋友,如果觉得不错麻烦给个好评~~!
Android中的JNI测试程序 最简单的实现JNI的测试代码,配合我的博客的博文学习
android jni 实现 RSA 3DES AES MD5 BASE64 加密,基于openssl
在android中使用jni,在jni中调用jni里面的方法
Android 串口读写程序 JNI代码程序
此外,在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。 应用层的...