用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象
SAF-Kotlin-log 是一个Android的日志框架,这几天我抽空重新更新了一下代码。
github地址:https://github.com/fengzhizi715/SAF-Kotlin-log
一. 打印几个Android常用的对象
1.1 Uri的打印
Uri uri = Uri.parse("http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic"); L.json(uri);
打印效果:
Uri.png
1.2 Bundle的打印
User u = new User(); u.userName = "tony"; u.password = "123456"; Bundle bundle = new Bundle(); bundle.putString("key1","this is key1"); bundle.putInt("key2",100); bundle.putBoolean("key3",true); bundle.putSerializable("key4",u); L.json(bundle);
打印效果:
Bundle.png
目前,它默认支持JSON字符串、集合、Map、Bundle、Intent、Reference、Throwable、Uri等类型的打印,分别做了特别的格式化处理。
二. 使用责任链模式,改造打印对象的方法
在使用责任链模式之前,json()方法是这样的,需要使用when表达式来判断某个类应该对应哪个方法来打印对象。
/** * 将任何对象转换成json字符串进行打印 */ @JvmStatic fun json(obj: Any?) { if (obj == null) { d("object is null") return } when(obj) { is String -> string2JSONString(obj) is Map<*, *> -> map2JSONString(obj) is Collection<*> -> collection2JSONString(obj) is Bundle -> bundle2JSONString(obj) is Reference<*> -> reference2JSON(obj) is Intent -> intent2JSON(obj) is Uri -> uri2JSON(obj) is Throwable -> throwable2JSONString(obj) else -> { try { val s = getMethodNames() var msg = obj.javaClass.toString() + LoggerPrinter.BR + "║ " val objStr = JSON.toJSONString(obj) val jsonObject = JSONObject(objStr) var message = jsonObject.toString(LoggerPrinter.JSON_INDENT) message = message.replace("\n".toRegex(), "\n║ ") println(String.format(s, msg+ message)) } catch (e: JSONException) { e("Invalid Json") } } } }
使用责任链模式之后,json()是这样的,一行代码代替了when表达式。
/** * 将任何对象转换成json字符串进行打印 */ @JvmStatic fun json(obj: Any?) { if (obj == null) { d("object is null") return } firstHandler.handleObject(obj) }
2.1 为何需要责任链模式?
目前日志类L只能打印几种类型的对象,或者是默认地将对象打印成json。如果要对某一个对象类做一些个性化的格式化并打印出来,按照原先的做法需要修改json()方法的when表达式。
为了符合“开闭原则”,对扩展开放、对修改关闭。我考虑使用责任链模式来替代when表达式,未来有其他需求只需增加一个单独的Handler即可。
2.2 如何使用责任链模式?
首先,定义一个基类的Handler用于对象的处理,这个Handler还会被赋予一个nextHandler表示责任链中的下一个处理者。如果当前的Handler处理不了,则交给下一个Handler来处理。
/** * Created by tony on 2017/11/27. */abstract class BaseHandler { // 责任链的下一个节点,即处理者 private var nextHandler: BaseHandler? = null // 捕获具体请求并进行处理,或是将请求传递到责任链的下一级别 fun handleObject(obj: Any) { if (obj == null) { return } if (!handle(obj)) { // 当前处理者不能胜任,则传递至责任链的下一节点 if (this.nextHandler != null) { this.nextHandler!!.handleObject(obj) } } } // 设置责任链中的下一个处理者 fun setNextHandler(nextHandler: BaseHandler) { this.nextHandler = nextHandler } // 定义链中每个处理者具体的处理方式 protected abstract fun handle(obj: Any): Boolean}
定义完基类的Handler之后,需要定义各个具体的Handler。以BundleHandler为例,它是专门用于格式化Bundle并打印出来。
import android.os.Bundleimport com.alibaba.fastjson.JSONimport com.safframework.log.Limport com.safframework.log.LoggerPrinterimport com.safframework.log.parser.Parserimport com.safframework.log.utils.Utilsimport org.json.JSONExceptionimport org.json.JSONObject/** * Created by tony on 2017/11/27. */class BundleHandler():BaseHandler(), Parser { override fun handle(obj: Any): Boolean { if (obj is Bundle) { val s = L.getMethodNames() println(String.format(s, parseString(obj))) return true } return false } override fun parseString(bundle: Bundle): String { var msg = bundle.javaClass.toString() + LoggerPrinter.BR + "║ " val jsonObject = JSONObject() for (key in bundle.keySet()) { val isPrimitiveType = Utils.isPrimitiveType(bundle.get(key)) try { if (isPrimitiveType) { jsonObject.put(key.toString(), bundle.get(key)) } else { jsonObject.put(key.toString(), JSONObject(JSON.toJSONString(bundle.get(key)))) } } catch (e: JSONException) { L.e("Invalid Json") } } var message = jsonObject.toString(LoggerPrinter.JSON_INDENT) message = message.replace("\n".toRegex(), "\n║ ") return msg + message }}
定义完各个Handler之后,需要把各个Handler串联起来。在日志类L中使用Kotlin的init代码块来做这件事,init代码块相当于Java的静态代码块。
private val handlers = ArrayList() private var firstHandler:BaseHandler init{ handlers.add(StringHandler()) handlers.add(CollectionHandler()) handlers.add(MapHandler()) handlers.add(BundleHandler()) handlers.add(IntentHandler()) handlers.add(UriHandler()) handlers.add(ThrowableHandler()) handlers.add(ReferenceHandler()) handlers.add(ObjectHandler()) val len = handlers.size for (i in 0..len - 1) { if (i > 0) { handlers[i - 1].setNextHandler(handlers[i]) } } firstHandler = handlers[0] }
做完这些之后,才能通过一行代码来处理各种对象。
firstHandler.handleObject(obj)
三. 自定义对象的解析处理
目前在框架中只能处理8种对象,或者使用默认的方式将对象打印成json风格。
如果有个性化的需求,可以自定义类来实现,只需继承BaseHandler。
例如,定义一个UserHandler
import com.safframework.log.L;import com.safframework.log.handler.BaseHandler;import org.jetbrains.annotations.NotNull;/** * Created by tony on 2017/11/27. */public class UserHandler extends BaseHandler { @Override protected boolean handle(@NotNull Object obj) { if (obj instanceof User) { User u = (User)obj; String s = L.getMethodNames(); System.out.println(String.format(s, u.userName+":"+u.password)); return true; } return false; }}
在使用UserHandler之前,使用默认的ObjectHandler将对象格式化后打印出来。L添加了UserHandler之后,再打印user对象就不再使用默认的ObjectHandler,而是使用UserHandler来格式化对象。
User u = new User(); u.userName = "tony"; u.password = "123456"; L.json(u); L.addCustomerHandler(new UserHandler()); L.json(u);
打印效果
自定义Handler.png四. 总结
这篇文章应该算是很久之前两篇文章的后续,现在越来越多的工具我开始使用Kotlin来开发。
更多相关文章
- SpannableString的使用方法
- Android(安卓)Binder机制 - defaultServiceManager()源码分析
- Android屏幕元素层次结构
- Android内存泄漏分析及调试
- android 手机滤镜
- Android(安卓)Studio——Android(安卓)TextUtils类介绍
- android中进度条―基础篇
- Android上下文服务管理查询过程
- Android开发AsyncTask异步处理任务