標籤:git contains exception tle ++ put XML builder _for
Android KLog原始碼分析
-
- Android KLog原始碼分析
-
- 代碼結構
- 詳細分析
- BaseLog
- FileLog
- JsonLog
- XmlLog
- 核心檔案KLogjava分析
- 遇到的問題
一直使用這個庫。但沒有細緻研究。今天就來研究一下。該庫的地址:
KLog,在這裡先感謝下作者。棒棒噠!
代碼結構
整個代碼的結構非常easy。例如以下:
library klog BaseLog.java FileLog.java JsonLog.java XmlLog.java KLog.java KLogUtil.java
共六個檔案:
- BaseLog.java,支援主要的log列印
- FileLog.java。支援以檔案的形式儲存log
- JsonLog.java,支援列印json對象和json數組
- XmlLog.java,支援列印Xml形式的log
詳細分析BaseLog
兩個方法:
public class BaseLog { private static final int MAX_LENGTH = 4000; public static void printDefault(int type, String tag, String msg) { int index = 0; int length = msg.length(); int countOfSub = length / MAX_LENGTH; if (countOfSub > 0) {// 超過指定長度,粉刺列印。這樣就避免了系統預設的log長度限制了 for (int i = 0; i < countOfSub; i++) { String sub = msg.substring(index, index + MAX_LENGTH); printSub(type, tag, sub); index += MAX_LENGTH; } printSub(type, tag, msg.substring(index, length));// 列印餘數部分 } else { printSub(type, tag, msg); } } private static void printSub(int type, String tag, String sub) { switch (type) { case KLog.V: Log.v(tag, sub); break; case KLog.D: Log.d(tag, sub); break; case KLog.I: Log.i(tag, sub); break; case KLog.W: Log.w(tag, sub); break; case KLog.E: Log.e(tag, sub); break; case KLog.A: Log.wtf(tag, sub); break; } }}
這裡突破了android系統的log字數限制,事實上就是超過字數限制後。採用分次列印的方法來列印,其它代碼不做分析,比較簡單。
FileLog
三個方法
public class FileLog { private static final String FILE_PREFIX = "KLog_"; private static final String FILE_FORMAT = ".log"; /** * @param tag log tag * @param targetDirectory log file save dir * @param fileName log file name * @param headString log file 檔案頭 * @param msg log file log內容主體 */ public static void printFile(String tag, File targetDirectory, @Nullable String fileName, String headString, String msg) { fileName = (fileName == null) ? getFileName() : fileName; if (save(targetDirectory, fileName, msg)) { Log.d(tag, headString + " save log success ! location is >>>" + targetDirectory.getAbsolutePath() + "/" + fileName); } else { Log.e(tag, headString + "save log fails !"); } } /** * @param dic log file save dir * @param fileName og file name * @param msg log file log內容主體 * @return true if save success */ private static boolean save(File dic, @NonNull String fileName, String msg) { File file = new File(dic, fileName); try { OutputStream outputStream = new FileOutputStream(file); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8"); outputStreamWriter.write(msg); outputStreamWriter.flush(); outputStream.close(); return true; } catch (FileNotFoundException e) { e.printStackTrace(); return false; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 當未設定檔案名稱時,隨機產生一個檔案名稱 * * @return default file name */ private static String getFileName() { Random random = new Random(); return FILE_PREFIX + Long.toString(System.currentTimeMillis() + random.nextInt(10000)).substring(4) + FILE_FORMAT; }}
JsonLog
JsonLog就更簡單了,僅僅有一個方法(本寶寶曾經還以為Json列印會非常麻煩呢)
public class JsonLog { public static void printJson(String tag, String msg, String headString) { String message; try { if (msg.startsWith("{")) {// 處理json對象 JSONObject jsonObject = new JSONObject(msg); message = jsonObject.toString(KLog.JSON_INDENT); } else if (msg.startsWith("[")) {// 處理json數組 JSONArray jsonArray = new JSONArray(msg); message = jsonArray.toString(KLog.JSON_INDENT); } else { message = msg; } } catch (JSONException e) { message = msg; } KLogUtil.printLine(tag, true);// 調用格式化方法 message = headString + KLog.LINE_SEPARATOR + message; String[] lines = message.split(KLog.LINE_SEPARATOR); for (String line : lines) { Log.d(tag, "║ " + line); } KLogUtil.printLine(tag, false);// 調用格式化方法 }}
XmlLog
兩個方法:
public class XmlLog { /** * 列印xml * * @param tag log tag * @param xml xml content * @param headString 檔案頭 */ public static void printXml(String tag, String xml, String headString) { if (xml != null) { xml = XmlLog.formatXML(xml); xml = headString + "\n" + xml; } else { xml = headString + KLog.NULL_TIPS; } KLogUtil.printLine(tag, true); String[] lines = xml.split(KLog.LINE_SEPARATOR); for (String line : lines) { if (!KLogUtil.isEmpty(line)) { Log.d(tag, "║ " + line); } } KLogUtil.printLine(tag, false); } /** * @param inputXML xml content * @return 格式化後的xml String */ private static String formatXML(String inputXML) { try { Source xmlInput = new StreamSource(new StringReader(inputXML)); StreamResult xmlOutput = new StreamResult(new StringWriter()); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.transform(xmlInput, xmlOutput); return xmlOutput.getWriter().toString().replaceFirst(">", ">\n"); } catch (Exception e) { e.printStackTrace(); return inputXML; } }}
細心的你會發現。不管是Json形式還是XML形式。調用的都是系統原生的方法來處理資料,因此又時候對熟悉熟悉java(或android)提供的方法還是非常方便的。哈哈。
上面用到的KLogUtil,例如以下:
public class KLogUtil { public static boolean isEmpty(String line) { return TextUtils.isEmpty(line) || line.equals("\n") || line.equals("\t") || TextUtils.isEmpty(line.trim()); } public static void printLine(String tag, boolean isTop) { if (isTop) { Log.d(tag, "╔═══════════════════════════════════════════════════════════════════════════════════════"); } else { Log.d(tag, "╚═══════════════════════════════════════════════════════════════════════════════════════"); } }}
核心檔案KLog.java分析
給方法主要提供了相似於系統log方法的不同重載,比較簡單,我這裡要講的是那個擷取log詳細有關的類名、方法名、行號等。與之相關的就是wrapperContent這種方法了。
private static String[] wrapperContent(int stackTraceIndex, String tagStr, Object... objects) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); StackTraceElement targetElement = stackTrace[stackTraceIndex]; String className = targetElement.getClassName();// 得到類名 String[] classNameInfo = className.split("\\.");// 第一種形式 if (classNameInfo.length > 0) { className = classNameInfo[classNameInfo.length - 1] + SUFFIX; } if (className.contains("$")) {//另外一種形式 className = className.split("\\$")[0] + SUFFIX; } String methodName = targetElement.getMethodName();//得到方法名 int lineNumber = targetElement.getLineNumber();//得到所在的行號 if (lineNumber < 0) { lineNumber = 0; } String tag = (tagStr == null ? className : tagStr); if (mIsGlobalTagEmpty && TextUtils.isEmpty(tag)) { tag = TAG_DEFAULT; } else if (!mIsGlobalTagEmpty) { tag = mGlobalTag; } // 得到訊息主體 String msg = (objects == null) ? NULL_TIPS : getObjectsString(objects); String headString = "[ (" + className + ":" + lineNumber + ")#" + methodName + " ] "; return new String[]{tag, msg, headString}; }/** * 得到訊息主體 * * @param objects 訊息對象數組 * @return 訊息主體字串 */ private static String getObjectsString(Object... objects) { if (objects.length > 1) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("\n"); for (int i = 0; i < objects.length; i++) { Object object = objects[i]; if (object == null) { stringBuilder.append(PARAM).append("[").append(i).append("]").append(" = ").append(NULL).append("\n"); } else { stringBuilder.append(PARAM).append("[").append(i).append("]").append(" = ").append(object.toString()).append("\n"); } } return stringBuilder.toString(); } else { Object object = objects[0]; return object == null ?
NULL : object.toString(); } }
分析完成,是不是非常easy,假設你看了這個庫的代碼。你會認為我的分析都是多餘的。
遇到的問題
在使用KLog列印json形式資訊時。假設網路請求時非同步,會導致KLog.json列印的格式出現錯亂。即一個結果還沒有全然列印出來。裡外一個就開始列印了,這個應該是並發導致的問題,之後我會在KLog的基礎上對這個問題進行最佳化的。
Android KLog原始碼分析