前言
自定义log时,往往需要我们把后台返回的json字符串格式化输出到控制台,方便我们调试。Android原生可以通过JSONObject等进行格式化,将字符串格式化。flutter中并没有那么便利的实现方式,因此需要我们手动转换。想直接看代码的可以直接点击 d_logger 或 github查看。这是本人编写的一个log日志管理,觉得对你有帮助的麻烦点个like,谢谢。
实现思路
在conver包下,dart为我们提供了json转换工具。可以利用这点,先把json字符串转换成相应的对象。由于json可能返回的是一个数组或对象,因此需要我们进行判断,获取正确的转换类型,再进行下一步转换操作。
if (json.startsWith("{")) { //is jsonObject
Map<String, dynamic> decode = JsonCodec().decode(json);
//...convert json
} else if (json.startsWith("[")) { //is jsonArray
List decode = JsonCodec().decode(json);
//...convert json
}
由于转换对象的层级不确定,即map或list都可能相互嵌套。在此可以利用递归,对元素进行遍历输出。定义convert方法,传入待解析对象。判断传入的对象类型:Map、List、String、num、bool,以此对不同类型进行格式化。
解析Map或List时,需要返回考虑以下几种结果:
1.集合不是任何字段的结果 ;
2.集合为某个字段的结果,需要区分集合为空、不为空两种格式化。
请注意1和4处,集合不为任何字段内容时,首尾和内容都需要换行进行显示。而当集合为某个字段内容时(2和3),头部需要紧随字段内容,且当集合为空,则不需要重新换行,直接响应尾部。循环递归时,可根据传入对应的判断进行调控。
解析String时,需要把内容加上 "" 并返回内容。
解析num和bool时,直接返回当前内容即可。
需要注意,为了能够让结果清晰明了,不同层级之前都需要加上对应的空格。递归时传入当前递归深度,根据深度获取前置空格。
///获取缩进空白符
String getDeepSpace(int deep) {
var tab = StringBuffer();
for (int i = 0; i < deep; i++) {
tab.write("\t");
}
return tab.toString();
}
按照以上思路,json格式化的最终代码如下:
/// [object] 解析的对象
/// [deep] 递归的深度,用来获取缩进的空白长度
/// [isObject] 用来区分当前map或list是不是来自某个字段,则不用显示缩进。单纯的map或list需要添加缩进
String _convert(dynamic object, int deep, {bool isObject = false}) {
var buffer = StringBuffer();
var nextDeep = deep + 1;
if (object is Map) {
var list = object.keys.toList();
if (!isObject) {//如果map来自某个字段,则不需要显示缩进
buffer.write("${getDeepSpace(deep)}");
}
buffer.write("{");
if (list.isEmpty) {//当map为空,直接返回‘}’
buffer.write("}");
}else {
buffer.write("\n");
for (int i = 0; i < list.length; i++) {
buffer.write("${getDeepSpace(nextDeep)}\"${list[i]}\":");
buffer.write(_convert(object[list[i]], nextDeep, isObject: true));
if (i < list.length - 1) {
buffer.write(",");
buffer.write("\n");
}
}
buffer.write("\n");
buffer.write("${getDeepSpace(deep)}}");
}
} else if (object is List) {
if (!isObject) {//如果list来自某个字段,则不需要显示缩进
buffer.write("${getDeepSpace(deep)}");
}
buffer.write("[");
if (object.isEmpty) {//当list为空,直接返回‘]’
buffer.write("]");
}else {
buffer.write("\n");
for (int i = 0; i < object.length; i++) {
buffer.write(_convert(object[i], nextDeep));
if (i < object.length - 1) {
buffer.write(",");
buffer.write("\n");
}
}
buffer.write("\n");
buffer.write("${getDeepSpace(deep)}]");
}
} else if (object is String) {//为字符串时,需要添加双引号并返回当前内容
buffer.write("\"$object\"");
} else if (object is num || object is bool) {//为数字或者布尔值时,返回当前内容
buffer.write(object);
} else {//如果对象为空,则返回null字符串
buffer.write("null");
}
return buffer.toString();
}
如果有更好的实现方式欢迎留言讨论~