Android中关于JNI 的学习(五)在C文件里使用LogCat

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中看到以下的记录:

Android中关于JNI 的学习(五)在C文件里使用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提供的系统库中。例如以下:

Android中关于JNI 的学习(五)在C文件里使用LogCat

5)通过这几步。我们就能够像在Android调试一样,在C/C++中去调试我们的程序了。

结束。


上一篇:手机换屏_20170828


下一篇:iOS Dev (50)用代码实现图片加圆角