Android logcat日志封裝
logcat痛點(diǎn)
在Android開發(fā)中使用logcat非常頻繁,logcat能幫我們定位問題,但是在日常使用中發(fā)現(xiàn)每次使用都需要傳遞tag,并且會遇到輸出頻率很高的log,在多人混合開發(fā)的場景下,不過濾很難找到自己打的log,調(diào)試別人代碼時看不懂他人輸出的log。這些問題會影響到整個開發(fā)效率,并且無法對整個項目的log進(jìn)行統(tǒng)一管理。
目的
為了方便管理和規(guī)范log輸出,增加logcat使用的便捷性封裝logcat需要滿足以下幾點(diǎn):
1、動態(tài)管理日志輸出
2、使用便捷,只需關(guān)注需要輸出的massage即可
3、日志信息顯示齊全,方便定位與統(tǒng)一
日志輸出開關(guān)
通過廣播及系統(tǒng)屬性控制日志的開關(guān),通過注冊LOG_SWITCH = "android.App.all.log" 廣播,用來控制所有app日志開關(guān),方便多app統(tǒng)一管理,另外通過注冊包名后綴+".log"廣播(如包名為:com.yxd.logtest,則action為:logtest.log),來控制當(dāng)前app的日志開關(guān),同時還將開關(guān)值存入到系統(tǒng)屬性中,以免退出后需重新打開。
通過adb模擬發(fā)送廣播,實(shí)現(xiàn)開關(guān)控制,adb命令:adb shell am broadcast -a android.app.all.log --ei status 1
public static void init(Context context) {
if (sContext != null){
return;
}
IntentFilter intentFilter = new IntentFilter();
//系統(tǒng)屬性名稱不可超過32字符,所以使用包名最后一段+.log 來做屬性名
String[] strings = context.getPackageName().split("\.");
intentFilter.addAction(strings[strings.length - 1] + ".log");
intentFilter.addAction(LOG_SWITCH);
context.registerReceiver(new LogSwitchReceiver(), intentFilter);
String allLog = SystemProperties.get(LOG_SWITCH);
String thisLog = SystemProperties.get(strings[strings.length - 1] + ".log");
if ((!thisLog.isEmpty() && "1".equals(thisLog)) || (!allLog.isEmpty() && "1".equals(allLog))) {
HQLog.SWITCH = true;
}
sContext = context;
}
static class LogSwitchReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(LOG_STATUS, 0);
Log.d("LogUtils", "LogSwitchReceiver action: " + intent.getAction() + " status: " + status);
SystemProperties.set(intent.getAction(), String.valueOf(status));
HQLog.SWITCH = status == 1;
}
}
如果為debug版本,則默認(rèn)打開日志輸出
public static boolean SWITCH = BuildConfig.DEBUG;
輸出格式
為了方便使用及定位,輸出時需要將類名及行數(shù)顯示,且在logcat上點(diǎn)擊該行可以直接定位到對應(yīng)輸出代碼,類似crash報錯日志,點(diǎn)擊藍(lán)色字體即可跳轉(zhuǎn)至輸出行
具體實(shí)現(xiàn)如下:
public static void e(String message) {
if (SWITCH) {
Log.e(getTag(), message);
}
}
private static String getTag() {
StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
String tag = null;
if (traceElements != null && traceElements.length > 4) {
StackTraceElement traceElement = traceElements[4];
tag = "(" + traceElement.getFileName() + ":" + traceElement.getLineNumber() + ")" + traceElement.getMethodName();
} else {
tag = "ULog";
}
return tag;
完整代碼
使用時需在application里面init一下
public class MyApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
LogUtils.init(this);
AppInfo.initContext(this);
}
public static Context getApplication(){
return mContext;
}
}
public class LogUtils {
public static String LOG_SWITCH = "android.app.all.log";
//log開關(guān)狀態(tài) 0關(guān) 1開
public static String LOG_STATUS = "status";
@SuppressLint("StaticFieldLeak")
private static Context sContext;
private static LogSwitchReceiver sLogSwitchReceiver = new LogSwitchReceiver();
public static void init(Context context) {
if (sContext != null){
return;
}
IntentFilter intentFilter = new IntentFilter();
//系統(tǒng)屬性名稱不可超過32字符,所以使用包名最后一段+.log 來做屬性名
String[] strings = context.getPackageName().split("\.");
intentFilter.addAction(strings[strings.length - 1] + ".log");
intentFilter.addAction(LOG_SWITCH);
context.registerReceiver(new LogSwitchReceiver(), intentFilter);
String allLog = SystemProperties.get(LOG_SWITCH);
String thisLog = SystemProperties.get(strings[strings.length - 1] + ".log");
if ((!thisLog.isEmpty() && "1".equals(thisLog)) || (!allLog.isEmpty() && "1".equals(allLog))) {
ULog.SWITCH = true;
}
sContext = context;
}
public static void release() {
if (sContext != null && sLogSwitchReceiver != null) {
sContext.unregisterReceiver(sLogSwitchReceiver);
}
}
static class LogSwitchReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(LOG_STATUS, 0);
Log.d("LogUtils", "LogSwitchReceiver action: " + intent.getAction() + " status: " + status);
SystemProperties.set(intent.getAction(), String.valueOf(status));
ULog.SWITCH = status == 1;
}
}
}
public class ULog {
public static boolean SWITCH = BuildConfig.DEBUG;
public static void v(String message) {
if (SWITCH) {
Log.v(getTag(), message);
}
}
public static void d(String message) {
if (SWITCH) {
Log.d(getTag(), message);
}
}
public static void i(String message) {
if (SWITCH) {
Log.i(getTag(), message);
}
}
public static void w(String message) {
if (SWITCH) {
Log.w(getTag(), message);
}
}
public static void e(String message) {
if (SWITCH) {
Log.e(getTag(), message);
}
}
public static void getStackTraceString(Throwable tr) {
if (SWITCH) {
Log.getStackTraceString(tr);
}
}
private static String getTag() {
StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
String tag = null;
if (traceElements != null && traceElements.length > 4) {
StackTraceElement traceElement = traceElements[4];
tag = "(" + traceElement.getFileName() + ":" + traceElement.getLineNumber() + ")" + traceElement.getMethodName();
} else {
tag = "ULog";
}
return tag;
}
private static String generateLogcatText(String msg, int place, String message) {
return generateLogcatText(Thread.currentThread().getStackTrace(), msg, place, message);
}
private static String generateLogcatText(StackTraceElement[] traceElements, String msg, int place, String message) {
try {
StringBuilder taskName = new StringBuilder();
if (traceElements != null && traceElements.length > place) {
StackTraceElement traceElement = traceElements[place];
taskName.append(traceElement.getMethodName()).append("() : ").append(message);
}
return taskName.toString();
} catch (Throwable throwable) {
return msg;
}
}
}






