android 字符串扩展,好用高扩展性的Android平台日志框架Slog

另外我们还可以通过Slog.getSetting()获取Setting对象之后,在任何时候对全局Log输出配置项进行修改。

基本使用

使用以下方式初始化Slog。

Slog.init(LogcatTree()).perfixTag(“TestSlog”).showThreadInfo(true);

打印普通日志

// 打印普通日志

Slog.d(“sky debug”);

Slog.i(“sky info”);

// 打印格式化字符串

Slog.d(“this is a format string log, str1 = %s, int value2 = %d, boolean3 = %b”, “string1”, 2, true);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

normal_log

打印错误日志

// 打印throwable

Slog.e(new Throwable());

Slog.w(new RuntimeException(), “test log with warn priority = %d”, Slog.WARN);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

error_warn_log

打印json和xml

json和xml字符串采用的日志级别都是Debug的。

打印json字符串

String jsonEmpty = “”;

String jsonEmpty2 = “{}”;

String jsonNull = null;

Slog.json(jsonEmpty);

Slog.json(jsonEmpty2);

Slog.json(jsonNull);

String json = “{‘xyy1’:[{‘test1’:‘test1’},{‘test2’:‘test2’}],‘xyy2’:{‘test3’:‘test3’,‘test4’:‘test4’}}”;

Slog.json(json);

String jsonArray =

"{ ‘employees’: [ {‘firstName’:‘John’, ‘lastName’:‘Doe’}, {‘firstName’:‘Anna’, ‘lastName’:‘Smith’}, "

+ “{‘firstName’:‘Peter’, ‘lastName’:‘Jones’}]}”;

Slog.json(jsonArray);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

json1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

json2

打印xml字符串

String androidXml = “<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>\n” +

"

" package=\“com.sky.tools\” >\n" +

“\n” +

"

" android:name=\“.application.MainApplication\”\n" +

" android:allowBackup=\“true\”\n" +

" android:icon=\“@mipmap/ic_launcher\”\n" +

" android:label=\“@string/app_name\”\n" +

" android:roundIcon=\“@mipmap/ic_launcher_round\”\n" +

" android:supportsRtl=\“true\”\n" +

" android:theme=\“@style/AppTheme\” >\n" +

" \n" +

" \n" +

" \n" +

“\n” +

" \n" +

" \n" +

" \n" +

"

\n" +

“\n” +

"

";

Slog.xml(androidXml);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

xml_log

打印对象

Slog 支持对对象的打印,其原理是给每个不同的对象类型添加对应的对象解析器,默认提供对数组,集合等解析,支持自定义对象解析器。

打印null对象

Slog.i(null);

Slog.i(“”);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

null_object

打印数组对象

// 全局多维对象数组

private static Object[] objectsArray = new Object[]{

new boolean[]{false, true, true, false},

new String[][]{

new String[]{“22”, “23”, “24”},

new String[]{“123”, “456”, “789”}},

new int[][][]{new int[][]{

new int[]{666, 555, 444},

new int[]{111, 222, 333, 444}},

new int[][]{

new int[]{1, 2, 3, 4, 5, 6},

new int[]{7878, 6565, 84155, 7542, 0}}}};

// 打印对象数组

Object[] objectArray = new Object[1024];

for (int i = 0; i < objectArray.length; i++) {

objectArray[i] = i;

}

Slog.i(objectArray);

// 打印String

String[] stringArray = new String[1024];

for (int i = 1024; i < stringArray.length + 1024; i++) {

stringArray[i - 1024] = "is " + i;

}

Slog.i(stringArray);

// 打印int数组

int[] intArray = new int[1024];

for (int i = 2048; i < intArray.length + 2048; i++) {

intArray[i - 2048] = i;

}

Slog.i(intArray);

// 打印多维数组

Slog.i(objectsArray);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

array_log

打印自定义对象解析器的对象

有如下一个Student类。

public class Student {

private int number;

private int age;

private String name;

private boolean isBoy;

public Student(int number, int age, String name, boolean isBoy){

this.number = number;

this.age = age;

this.name = name;

this.isBoy = isBoy;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

public boolean isBoy() {

return isBoy;

}

public int getNumber() {

return number;

}

}

自定义一个Student对象解析器,所有的对象解析器都必须要实现Parser接口。

public class StudentParser implements Parser {

@Override

public Class getParseType() {

return Student.class;

}

@Override

public String parseToString(Student student) {

return student.getName() + " is a " + student.getAge() + " years old " + (student.isBoy() ? “boy” : “girl”);

}

}

上面的parseToString将在解析对象时调用,由它返回被解析的对象最终要表示的字符串内容。

// 没有添加解析器之前

Student s = new Student(12345, 54, “sky”, true);

Slog.d(s);

// 添加解析器之后

Slog.addObjectParser(new StudentParser());

Slog.d(s);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

object_parser

打印Collection对象

这里以Map举例。

// empty map

Map map = new HashMap<>();

Slog.d(map);

// int map

Map intMap = new ConcurrentHashMap<>();

intMap.put(1, 2);

intMap.put(1543, 2745867);

intMap.put(17687, 27678);

intMap.put(76781, 27678);

intMap.put(1786768, 26786);

Slog.d(intMap);

// Object Map

Map objectStringMap = new LinkedHashMap<>();

objectStringMap.put(new Object(), “11223786”);

objectStringMap.put(new Object(), “475775486”);

objectStringMap.put(new Object(), “7856874757”);

Slog.d(objectStringMap);

// student Map

map.put(12345, new Student(12345, 54, “sky”, true));

map.put(123456, new Student(123456, 56, “sky2”, true));

map.put(1234567, new Student(1234567, 15, “sky3”, true));

map.put(12345678, new Student(12345678, 25, “sky4”, true));

map.put(1234555, new Student(1234555, 35, “sky5”, true));

map.put(12345444, new Student(12345444, 45, “sky6”, true));

Slog.d(map);

// map itself

Map map1 = new Hashtable<>();

//noinspection CollectionAddedToSelf,unchecked

map1.put(map1, map1);

Slog.d(map1);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

map_log

指定临时的配置项打印日志

前面的示例都是不修改输出配置项时打印的日志,但是在很多时候我们可能根据不同的场景,需要采用不同的日志输出配置。

除了前面说的使用Slog.getSetting()方法获取Setting对象之后,修改全局输出配置外,Slog框架还支持指定临时输出配置,只在下次当前线程打印日志时生效一次的方式更改日志输出效果。

具体包括以下几个方法。

Slog.t() // 指定下一次当前线程打印日志的tag,最终输出的日志的Tag组合为: prefixTag-tag

Slog.th() // 指定下一次当前线程打印日志是否显示线程信息

Slog.m() // 指定下一次当前线程打印日志显示的调用stack中方法的数目

Slog.o() // 指定下一次当前线程打印日志显示stack方法时的偏移值

Slog.s() // 指定下一次当前线程打印日志是否采用简单模式输出

上面的配置方法可以单个使用也可以组合使用。

单个使用

Slog.t(“custom22”).i(“set tag to custom”);

Slog.th(false).i(“hide the threadInfo”);

Slog.m(0).i(“test 0 method count print, so hide track”);

Slog.m(3).i(“test three method count println”);

Slog.o(1).i(“method offset 1”);

Slog.s(true).i(“set to simple mode”);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

temp_setting_log

联合使用

Slog.s(false).t(“fiveSetting”).th(true).m(5).o(2).i(“this time set five temp setting for test”);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

five_temp_setting_log

添加日志适配器

Slog框架目前只提供一个实现的日志适配器LogcatTree,本框架支持自定义日志适配器,所有的日志适配器都必须要继承Tree抽象类或者其子类,为了保证足够的扩展性,我们在Tree的接口中除了可以接收到封装处理好
的日志之外,也可以对原始的日志数据进行处理。

自定义一个FileTree。

public class FileTree extends Tree {

// … 还有其他的方法也可以根据需要复写

// 处理对象类型的日志,注意该接口方法,也可以根据原始的`originalObject`参数进行自定义处理

@Override

protected void prepareObjectLog(int priority, String tag, String[] compoundMessages, @Nullable Object originalObject) {

super.prepareObjectLog(priority, tag, compoundMessages, originalObject);

}

// 处理String类型的日志,注意该接口方法,也可以根据原始的`originalMessage`参数进行自定义处理

@Override

protected void prepareStringLog(int priority, String tag, Throwable t, String[] compoundMessages, @Nullable String originalMessages, @Nullable Object… args) {

super.prepareStringLog(priority, tag, t, compoundMessages, originalMessages, args);

}

// 该方法为必须要实现的父类抽象方法

@Override

protected void log(int priority, String tag, String message) {

// … 省略代码将日志保存到文件中

}

}

将其添加到日志适配器列表中,以后就可以正常使用了。

Slog.plantTree(new FileTree());

注意: 在每个日志适配器中,我们可以根据需要最终自己确定将组装之后的日志或者原始日志如何处理。

自定义日志组装器

通过继承LogAssembler抽象类,我们可以实现自己定义的日志组装器。

public class SimpleLogAssembler extends LogAssembler {

@Override

protected void onFormatModeLogMethodStackTrace(List compoundMessagesList, int methodCount, int stackOffset,

StackTraceElement[] trace) {

for (int i = methodCount; i > 0; i–) {

int stackIndex = i + stackOffset;

if (stackIndex >= trace.length) {

continue;

}

//noinspection StringBufferReplaceableByString

StringBuilder builder = new StringBuilder();

builder.append(getSimpleClassName(trace[stackIndex].getClassName()))

.append(“.”)

.append(trace[stackIndex].getMethodName())

.append(“(”)

.append(trace[stackIndex].getFileName())

.append(“:”)

.append(trace[stackIndex].getLineNumber())

.append(“)”);

compoundMessagesList.add(builder.toString());

}

}

@Override

protected void onFormatModeLogThreadInfo(List compoundMessagesList, Thread curThread) {

compoundMessagesList.add(Helper.createThreadInfo(curThread));

}

@Override

protected void onFormatModeLogContent(List compoundMessagesList, Throwable t, Object originalObject, Object[] args) {

String[] compoundMessages = compoundMessage(t, originalObject, args);

for (String compoundMessage : compoundMessages) {

String[] splitMessages = compoundMessage.split(LINE_SEPARATOR);

Collections.addAll(compoundMessagesList, splitMessages);

}

}

}

以上三个方法是子类必须要实现的,还有其他的方法子类可以选择性的复写。

以下是调用实例。

Slog.setLogAssembler(new SimpleLogAssembler());

Slog.i(“set log assembler to simple”);

Slog.m(10).i(“simple log assembler set methodCount to 10”);

// 设置为null,将使用默认的日志组装器

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取
Object originalObject, Object[] args) {

String[] compoundMessages = compoundMessage(t, originalObject, args);

for (String compoundMessage : compoundMessages) {

String[] splitMessages = compoundMessage.split(LINE_SEPARATOR);

Collections.addAll(compoundMessagesList, splitMessages);

}

}

}

以上三个方法是子类必须要实现的,还有其他的方法子类可以选择性的复写。

以下是调用实例。

Slog.setLogAssembler(new SimpleLogAssembler());

Slog.i(“set log assembler to simple”);

Slog.m(10).i(“simple log assembler set methodCount to 10”);

// 设置为null,将使用默认的日志组装器

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-FRcG1zww-1719167818104)]

[外链图片转存中…(img-ZNnQ5Yb6-1719167818105)]

[外链图片转存中…(img-A9mlrYEk-1719167818105)]

[外链图片转存中…(img-YPhElakT-1719167818106)]

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码 【微信小程序-毕设期末大作业】微信小程序源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值