用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象

简介: 用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象

一. 打印几个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);


打印效果:


image.png

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);


打印效果:


image.png

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.Bundle
import com.alibaba.fastjson.JSON
import com.safframework.log.L
import com.safframework.log.LoggerPrinter
import com.safframework.log.parser.Parser
import com.safframework.log.utils.Utils
import org.json.JSONException
import org.json.JSONObject
/**
 * Created by tony on 2017/11/27.
 */
class BundleHandler():BaseHandler(), Parser<Bundle> {
    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<BaseHandler>()
    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);


打印效果


image.png

自定义Handler.png


四. 总结



这篇文章应该算是很久之前两篇文章的后续,现在越来越多的工具我开始使用Kotlin来开发。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
21天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
22天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
1月前
|
调度 数据库 Android开发
构建高效Android应用:Kotlin协程的实践与优化
在Android开发领域,Kotlin以其简洁的语法和平台友好性成为了开发的首选语言。其中,Kotlin协程作为处理异步任务的强大工具,它通过提供轻量级的线程管理机制,使得开发者能够在不阻塞主线程的情况下执行后台任务,从而提升应用性能和用户体验。本文将深入探讨Kotlin协程的核心概念,并通过实例演示如何在实际的Android应用中有效地使用协程进行网络请求、数据库操作以及UI的流畅更新。同时,我们还将讨论协程的调试技巧和常见问题的解决方法,以帮助开发者避免常见的陷阱,构建更加健壮和高效的Android应用。
36 4
|
1月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【2月更文挑战第31天】 在移动开发领域,性能优化和流畅的用户体验一直是开发者追求的目标。随着Kotlin语言的流行,其异步编程解决方案——协程(Coroutines),为Android应用带来了革命性的并发处理能力。本文将深入探讨Kotlin协程的核心概念、设计原理以及在Android应用中的实际应用案例,旨在帮助开发者掌握这一强大的工具,从而提升应用的性能和响应能力。
|
23天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
28天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
17 4
|
6天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
10 0
|
17天前
|
移动开发 API Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【4月更文挑战第7天】 在移动开发领域,性能优化和应用响应性的提升一直是开发者追求的目标。近年来,Kotlin语言因其简洁性和功能性在Android社区中受到青睐,特别是其对协程(Coroutines)的支持,为编写异步代码和处理并发任务提供了一种更加优雅的解决方案。本文将探讨Kotlin协程在Android开发中的应用,揭示其在提高应用性能和简化代码结构方面的潜在优势,并展示如何在实际项目中实现和优化协程。
|
1月前
|
移动开发 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优势
在移动开发领域,尤其是针对Android平台,性能优化和流畅的用户体验始终是开发者追求的核心目标。近年来,Kotlin语言凭借其简洁性和功能性成为Android开发的新宠,特别是Kotlin协程的引入,为编写异步代码提供了一种全新的范式。本文将深入探讨Kotlin协程在Android应用开发中的应用及其带来的优势,旨在帮助开发者理解并运用协程来提高应用的性能和响应性。
|
1月前
|
存储 数据库 Android开发
构建高效Android应用:Kotlin协程的全面应用
在现代Android开发中,Kotlin协程作为一种优化异步编程和提升应用性能的强大工具,已经受到越来越多开发者的关注。本文将深入探讨Kotlin协程的核心概念、设计原理以及如何在实际Android项目中实现高效的协程应用。我们将从基础出发,逐步揭示协程如何简化线程管理,提供流畅的代码结构,并通过实际案例分析其在网络请求、数据库操作和UI响应中的应用效果。