編輯:關於Android編程
####################################################
使用NDK,就一定會接觸到log的使用。已經接觸了一段時間的NDK開發,也對log的使用做了一些總結,但基本上都是學習別人的方法,在自己實際使用的過程中,並不能趁心如意。所以,這一次對log的使用做一個全面的學習和復習。
####################################################
如何將so庫裡面的信息輸出到logcat中?可以使用android/log.h中的語句進行輸出
讓我們先看看log.h中有哪些需要了解的地方
log.h文件一般在$(NDK_HOME)/platforms/android-*/arch-*/usr/include/android之中
雖然有很多版本的log.h文件,但是沒有任何變化
基本內容如下:
1.NDK log支持在運行時發送信息到android內核日志緩沖區,這樣就可以通過logcat進行訪問
2.每個日志消息必須包含3部分:優先等級(priority),日志標簽(log tag)以及信息(text)
3.標簽相對應於發送日志信息的組件
4.如果日志消息文本過大,可能會被截斷。日志消息文本的的長度會有限制,比如最大1023個字節(下面會有測試)
5.如果日志消息的末尾沒有換行符,那麼會自動添加一個換行符(下面會有測試)。所以,想要多次輸出信息,但在logcat上顯示在同一行是不可能的。
同時log.h文件中也提醒我們適度使用日志,它給出了3條理由:
1)發送日志消息會使用CPU,這樣會減慢你的應用程序和系統;
2)循環日志緩沖區非常的小(<64KB),所以如果你發送了大量的日志信息,那麼可能會影響系統以及應用程序的一些重要的日志信息的推送;
3)在正式版本中,不應該發送任何日志信息,除非在一些特殊情況下。
下面來看一看具體的實現代碼:
對於優先等級,log.h中定義了一個枚舉:
/* * Android log priority values, in ascending priority order. */ 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;
/* * 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 ;函數功能:發送一條格式化的字符串,使用方法就像C語言中的printf函數。
參數:
1.prio-int類型,優先等級,使用枚舉android_LogPriority中的定義
2.tag-const char*類型,標簽,對應於發送消息的組件
3.fmt-const char*類型,格式化字符串,例如:“hi, %s”
4....-占位符,輸出日志信息
note:如果你使用GNUC編譯器的話,還會使用__attribute__,這裡不多介紹,感興趣的可以查找資料
既然log.h文件已經大致介紹完畢,那麼開始一個小小的demo來使用一下:
本次demo實現功能:
1)連續2次輸出文本“Hello, World”,判斷是否會自動添加換行符;
2)輸出文本“Hi, zj\n”,判斷有了換行符後,是否還會添加;
3)輸出文本“One, Two\nThree, Four”,判斷中間有換行符後是否會截斷輸出;
4)輸出1200個數字,從0開始,每100個加1,判斷文本是否會被截斷;
制作so庫的方法:android NDK JNI so文件的制作和使用-http://blog.csdn.net/u012005313/article/details/52005958
下面貼出主要代碼:
MainActivity:
package com.zj.logdemo; import android.app.Activity; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends Activity { static { System.loadLibrary("LogDemo"); } public native void test(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); test(); } }
com_zj_logdemo_MainActivity.h:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include/* Header for class com_zj_logdemo_MainActivity */ #ifndef _Included_com_zj_logdemo_MainActivity #define _Included_com_zj_logdemo_MainActivity #ifdef __cplusplus extern "C" { #endif #undef com_zj_logdemo_MainActivity_BIND_ABOVE_CLIENT #define com_zj_logdemo_MainActivity_BIND_ABOVE_CLIENT 8L #undef com_zj_logdemo_MainActivity_BIND_ADJUST_WITH_ACTIVITY #define com_zj_logdemo_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L #undef com_zj_logdemo_MainActivity_BIND_ALLOW_OOM_MANAGEMENT #define com_zj_logdemo_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L #undef com_zj_logdemo_MainActivity_BIND_AUTO_CREATE #define com_zj_logdemo_MainActivity_BIND_AUTO_CREATE 1L #undef com_zj_logdemo_MainActivity_BIND_DEBUG_UNBIND #define com_zj_logdemo_MainActivity_BIND_DEBUG_UNBIND 2L #undef com_zj_logdemo_MainActivity_BIND_EXTERNAL_SERVICE #define com_zj_logdemo_MainActivity_BIND_EXTERNAL_SERVICE -2147483648L #undef com_zj_logdemo_MainActivity_BIND_IMPORTANT #define com_zj_logdemo_MainActivity_BIND_IMPORTANT 64L #undef com_zj_logdemo_MainActivity_BIND_NOT_FOREGROUND #define com_zj_logdemo_MainActivity_BIND_NOT_FOREGROUND 4L #undef com_zj_logdemo_MainActivity_BIND_WAIVE_PRIORITY #define com_zj_logdemo_MainActivity_BIND_WAIVE_PRIORITY 32L #undef com_zj_logdemo_MainActivity_CONTEXT_IGNORE_SECURITY #define com_zj_logdemo_MainActivity_CONTEXT_IGNORE_SECURITY 2L #undef com_zj_logdemo_MainActivity_CONTEXT_INCLUDE_CODE #define com_zj_logdemo_MainActivity_CONTEXT_INCLUDE_CODE 1L #undef com_zj_logdemo_MainActivity_CONTEXT_RESTRICTED #define com_zj_logdemo_MainActivity_CONTEXT_RESTRICTED 4L #undef com_zj_logdemo_MainActivity_MODE_APPEND #define com_zj_logdemo_MainActivity_MODE_APPEND 32768L #undef com_zj_logdemo_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING #define com_zj_logdemo_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L #undef com_zj_logdemo_MainActivity_MODE_MULTI_PROCESS #define com_zj_logdemo_MainActivity_MODE_MULTI_PROCESS 4L #undef com_zj_logdemo_MainActivity_MODE_NO_LOCALIZED_COLLATORS #define com_zj_logdemo_MainActivity_MODE_NO_LOCALIZED_COLLATORS 16L #undef com_zj_logdemo_MainActivity_MODE_PRIVATE #define com_zj_logdemo_MainActivity_MODE_PRIVATE 0L #undef com_zj_logdemo_MainActivity_MODE_WORLD_READABLE #define com_zj_logdemo_MainActivity_MODE_WORLD_READABLE 1L #undef com_zj_logdemo_MainActivity_MODE_WORLD_WRITEABLE #define com_zj_logdemo_MainActivity_MODE_WORLD_WRITEABLE 2L #undef com_zj_logdemo_MainActivity_DEFAULT_KEYS_DIALER #define com_zj_logdemo_MainActivity_DEFAULT_KEYS_DIALER 1L #undef com_zj_logdemo_MainActivity_DEFAULT_KEYS_DISABLE #define com_zj_logdemo_MainActivity_DEFAULT_KEYS_DISABLE 0L #undef com_zj_logdemo_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL #define com_zj_logdemo_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L #undef com_zj_logdemo_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL #define com_zj_logdemo_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L #undef com_zj_logdemo_MainActivity_DEFAULT_KEYS_SHORTCUT #define com_zj_logdemo_MainActivity_DEFAULT_KEYS_SHORTCUT 2L #undef com_zj_logdemo_MainActivity_RESULT_CANCELED #define com_zj_logdemo_MainActivity_RESULT_CANCELED 0L #undef com_zj_logdemo_MainActivity_RESULT_FIRST_USER #define com_zj_logdemo_MainActivity_RESULT_FIRST_USER 1L #undef com_zj_logdemo_MainActivity_RESULT_OK #define com_zj_logdemo_MainActivity_RESULT_OK -1L /* * Class: com_zj_logdemo_MainActivity * Method: test * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zj_logdemo_MainActivity_test (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include#include #include #include #include "com_zj_logdemo_MainActivity.h" using namespace std; extern "C" { /* * Class: com_zj_logdemo_MainActivity * Method: test * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zj_logdemo_MainActivity_test (JNIEnv *env, jobject obj) { __android_log_print(ANDROID_LOG_INFO, "zj", "%s", "Hello, World"); __android_log_print(ANDROID_LOG_INFO, "zj", "%s", "Hello, World"); __android_log_print(ANDROID_LOG_INFO, "zj", "%s", "Hi,zj\n"); __android_log_print(ANDROID_LOG_INFO, "zj", "%s", "One, Two\nThree, Four"); stringstream ss; for (int i=0; i<1200; i++) { ss << i/100; } __android_log_print(ANDROID_LOG_INFO, "zj", "%s", ss.str().c_str()); } }
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := LogDemo LOCAL_SRC_FILES := main.cpp LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -lm -llog include $(BUILD_SHARED_LIBRARY)
APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions APP_ABI := armeabi-v7a #這句是設置生成的cpu指令類型,提示,目前絕大部分安卓手機支持armeabi,libs下太多類型,編譯進去 apk 包會過大 APP_PLATFORM := android-8 #這句是設置最低安卓平台,可以不弄
輸出:
根據顯示的結果可知:
1)如果信息末尾沒有換行符,那麼會自動添加;同時信息中間出現換行符不影響末尾自動添加。
2)文本過長會有截斷,說明對於每次發送的信息有長度限制。
####################################################################
上一步我們已經成功實現了NDK log日志的輸出,但是顯而易見的,直接調用log.h的函數進行日志輸出比較麻煩。網上流傳著一組宏定義:
#define TAG "zj" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
修改main.cpp:
#include#include #include #include #include "com_zj_logdemo_MainActivity.h" using namespace std; extern "C" { #define TAG "zj" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) /* * Class: com_zj_logdemo_MainActivity * Method: test * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zj_logdemo_MainActivity_test (JNIEnv *env, jobject obj) { LOGI("Hello everybody"); LOGD("%d + %d = %d", 1, 1, 2); } }
這樣,coding的效率就提高了
################################################################3
就像log.h裡面說的,當你進行開發的時候,可能需要很多的日志輸出,但當你發布正式版本時,就應該盡量避免日志的輸出。
如果使用上述方法,在發布正式版本的時候必須逐行注釋掉日志,耗費時間。同時,如果在運行過程中出現問題,又必須重新輸出日志,不利於開發。可以對上述代碼再做一次封裝:
#if 1 #define log_print_verbose(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) #define log_print_debug(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define log_print_info(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define log_print_warn(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define log_print_error(...) __android_log_print(ANROID_LOG_ERROR, TAG, __VA_ARGS__) #else #define log_print_verbose(...) #define log_print_debug(...) #define log_print_info(...) #define log_print_warn(...) #define log_print_error(...) #endif #define LOGV(...) log_print_verbose(__VA_ARGS__) #define LOGD(...) log_print_debug(__VA_ARGS__) #define LOGI(...) log_print_info(__VA_ARGS__) #define LOGW(...) log_print_warn(__VA_ARGS__) #define LOGE(...) log_print_error(__VA_ARGS__)
main.cpp如下:
#include#include #include #include #include "com_zj_logdemo_MainActivity.h" using namespace std; extern "C" { #define TAG "test" #if 1 #define log_print_verbose(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) #define log_print_debug(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define log_print_info(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define log_print_warn(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define log_print_error(...) __android_log_print(ANROID_LOG_ERROR, TAG, __VA_ARGS__) #else #define log_print_verbose(...) #define log_print_debug(...) #define log_print_info(...) #define log_print_warn(...) #define log_print_error(...) #endif #define LOGV(...) log_print_verbose(__VA_ARGS__) #define LOGD(...) log_print_debug(__VA_ARGS__) #define LOGI(...) log_print_info(__VA_ARGS__) #define LOGW(...) log_print_warn(__VA_ARGS__) #define LOGE(...) log_print_error(__VA_ARGS__) /* * Class: com_zj_logdemo_MainActivity * Method: test * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zj_logdemo_MainActivity_test (JNIEnv *env, jobject obj) { LOGI("Hello everybody"); LOGD("%d + %d = %d", 1, 1, 2); } }
結果:
發布正式版本
main.cpp如下:
#include#include #include #include #include "com_zj_logdemo_MainActivity.h" using namespace std; extern "C" { #define TAG "zj" #if 0 #define log_print_verbose(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) #define log_print_debug(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define log_print_info(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define log_print_warn(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define log_print_error(...) __android_log_print(ANROID_LOG_ERROR, TAG, __VA_ARGS__) #else #define log_print_verbose(...) #define log_print_debug(...) #define log_print_info(...) #define log_print_warn(...) #define log_print_error(...) #endif #define LOGV(...) log_print_verbose(__VA_ARGS__) #define LOGD(...) log_print_debug(__VA_ARGS__) #define LOGI(...) log_print_info(__VA_ARGS__) #define LOGW(...) log_print_warn(__VA_ARGS__) #define LOGE(...) log_print_error(__VA_ARGS__) /* * Class: com_zj_logdemo_MainActivity * Method: test * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zj_logdemo_MainActivity_test (JNIEnv *env, jobject obj) { LOGI("Hello everybody"); LOGD("%d + %d = %d", 1, 1, 2); } }
####################################################################
在使用過程中,可能你想要把代碼移植到C/C++工程中,但是無法使用__android_log_print函數,所以必須再次封裝:、
新建文件logUtil.hpp
#ifndef LOGUTIL_HPP #define LOGUTIL_HPP #define NDK_LOG false #if NDK_LOG #include #include#endif #define TAG "zj" #if NDK_LOG #define log_print_verbose(fmt, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, fmt, __VA_ARGS__) #define log_print_debug(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, __VA_ARGS__) #define log_print_info(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, __VA_ARGS__) #define log_print_warn(fmt, ...) __android_log_print(ANDROID_LOG_WARN, TAG, fmt, __VA_ARGS__) #define log_print_error(fmt, ...) __android_log_print(ANROID_LOG_ERROR, TAG, fmt, __VA_ARGS__) #else #define log_print_verbose(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_debug(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_info(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_warn(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_error(fmt, ...) printf(fmt, ##__VA_ARGS__) #endif #define LOGV(fmt, ...) log_print_verbose(fmt, ##__VA_ARGS__) #define LOGD(fmt, ...) log_print_debug(fmt, ##__VA_ARGS__) #define LOGI(fmt, ...) log_print_info(fmt, ##__VA_ARGS__) #define LOGW(fmt, ...) log_print_warn(fmt, ##__VA_ARGS__) #define LOGE(fmt, ...) log_print_error(fmt, ##__VA_ARGS__) #endif // LOGUTIL_HPP
下面測試一個小demo:
新建一個qt工程-qt_log
新建main.cpp:
#include
#include "logutil.hpp"
using namespace std;
int main(int argc, char* argv[])
{
LOGI("Hello World\n");
LOGW("Hi %s\n", "zj");
return 0;
}
結果:
運行成功
注意:在C++項目中,無法實現自動換行功能。所以在每條日志的第一條字符串末尾必須顯式加入'\n'換行符。
#########################################################
同樣的,在C/C++項目中,我們也想要在正式版本中不輸出日志,所以最終的logUtil.hpp可以修改如下:
#ifndef LOGUTIL_HPP #define LOGUTIL_HPP #define NDK_LOG false #define C_LOG true #if NDK_LOG #include #include#endif #define TAG "zj" #if NDK_LOG #define log_print_verbose(fmt, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, fmt, __VA_ARGS__) #define log_print_debug(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, __VA_ARGS__) #define log_print_info(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, __VA_ARGS__) #define log_print_warn(fmt, ...) __android_log_print(ANDROID_LOG_WARN, TAG, fmt, __VA_ARGS__) #define log_print_error(fmt, ...) __android_log_print(ANROID_LOG_ERROR, TAG, fmt, __VA_ARGS__) #elif C_LOG #define log_print_verbose(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_debug(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_info(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_warn(fmt, ...) printf(fmt, ##__VA_ARGS__) #define log_print_error(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define log_print_verbose(fmt, ...) #define log_print_debug(fmt, ...) #define log_print_info(fmt, ...) #define log_print_warn(fmt, ...) #define log_print_error(fmt, ...) #endif #define LOGV(fmt, ...) log_print_verbose(fmt, ##__VA_ARGS__) #define LOGD(fmt, ...) log_print_debug(fmt, ##__VA_ARGS__) #define LOGI(fmt, ...) log_print_info(fmt, ##__VA_ARGS__) #define LOGW(fmt, ...) log_print_warn(fmt, ##__VA_ARGS__) #define LOGE(fmt, ...) log_print_error(fmt, ##__VA_ARGS__) #endif // LOGUTIL_HPP
本文實例講述了Android DigitalClock組件用法。分享給大家供大家參考,具體如下:DigitalClock組件的使用很簡單,先看看效果圖:DigitalCl
1、為什麼要有AIDL? 無論學什麼東西,最先得弄明白為什麼要有這個東西,不要說存在即是合理,存在肯定合理,但是你還是沒有明白。對於AIDL有一些人的淺顯概念就是,AID
在前面的博客中,小編介紹了Android的極光推送以及如何實現登錄的一個小demo,對於xml布局頁面,擺控件這塊的內容,小編還不是很熟練,今天小編主要簡單總結一下在An
有網友安裝了“天天酷跑專用修改(超哥破解)”、“妖艷制作”和“讓任何人都驚喜的東西”