# JSON 工具
MT JSON 库提供了轻量高效的 JSON 解析和生成功能,基于 minimal-json 实现,并为 UI 组件提供了数据双向绑定的便捷方法。
# 概述
MT JSON 库具有以下特点:
- 轻量高效:基于 minimal-json 库实现,体积小、性能优
- 简洁易用:提供链式调用的 API,代码简洁清晰
- UI 数据绑定:提供 UI 组件与 JSON 数据的双向绑定功能
- 类型安全:完整的类型判断和转换方法
主要功能包括:
- 解析 JSON 字符串
- 创建和修改 JSON 对象和数组
- UI 组件数据的自动保存和恢复
- 格式化输出 JSON 文本
# 核心类
# JSON
JSON 工具类提供了创建 JSON 值和解析 JSON 字符串的静态方法。
# 创建 JSON 值
// 创建基本类型值
JSONValue value1 = JSON.value(true); // 布尔值
JSONValue value2 = JSON.value(42); // 整数
JSONValue value3 = JSON.value(3.14); // 浮点数
JSONValue value4 = JSON.value("Hello"); // 字符串
// 创建空对象和数组
JSONObject obj = JSON.object();
JSONArray arr = JSON.array();
方法列表:
value(boolean)- 创建布尔值value(int)- 创建整数值value(long)- 创建长整数值value(float)- 创建浮点数值value(double)- 创建双精度浮点数值value(String)- 创建字符串值array()- 创建空 JSON 数组object()- 创建空 JSON 对象
# 常量
JSONValue nullValue = JSON.NULL; // JSON null 值
JSONValue trueValue = JSON.TRUE; // JSON true 值
JSONValue falseValue = JSON.FALSE; // JSON false 值
# 解析 JSON
// 从字符串解析
String jsonText = "{\"name\":\"MT\",\"version\":3}";
JSONObject obj = JSON.parse(jsonText).asObject();
// 也可以直接使用 JSONObject 的构造函数
JSONObject obj2 = new JSONObject(jsonText);
// 从 Reader 解析
Reader reader = new FileReader("config.json");
JSONValue value = JSON.parse(reader);
方法列表:
parse(String)- 解析 JSON 字符串parse(Reader)- 从 Reader 解析 JSON
# JSONObject
JSONObject 表示一个 JSON 对象,包含一组键值对。
# 添加和设置值
JSONObject obj = new JSONObject();
// add() 方法 - 快速添加,不检查重复键
obj.add("name", "MT Manager")
.add("version", 3)
.add("enabled", true);
// put() 方法 - 设置值,会替换已存在的键
obj.put("version", 4); // 更新 version 的值
// 移除键值对
obj.remove("enabled");
add() 和 put() 的区别:
add()不检查键是否已存在,直接追加到末尾,性能更高,适合构建新对象put()会查找并替换已存在的键,性能较低,适合修改现有对象
方法列表:
add(String name, JSONValue value)- 添加 JSON 值add(String name, int/long/float/double/boolean/String value)- 添加基本类型值put(String name, JSONValue value)- 设置 JSON 值put(String name, int/long/float/double/boolean/String value)- 设置基本类型值remove(String name)- 移除指定键
# 获取值
JSONObject obj = new JSONObject("{\"name\":\"MT\",\"age\":3,\"active\":true}");
// 获取 JSONValue
JSONValue value = obj.get("name");
// 获取基本类型(带默认值)
String name = obj.getString("name", "Unknown");
int age = obj.getInt("age", 0);
boolean active = obj.getBoolean("active", false);
// 获取嵌套对象和数组
JSONObject nested = obj.getJSONObject("config");
JSONArray items = obj.getJSONArray("items");
方法列表:
get(String name)- 获取 JSONValue,不存在时返回 nullgetBoolean(String name, boolean defaultValue)- 获取布尔值getInt(String name, int defaultValue)- 获取整数getLong(String name, long defaultValue)- 获取长整数getFloat(String name, float defaultValue)- 获取浮点数getDouble(String name, double defaultValue)- 获取双精度浮点数getString(String name, String defaultValue)- 获取字符串getJSONObject(String name)- 获取嵌套对象getJSONArray(String name)- 获取数组
# 查询方法
JSONObject obj = new JSONObject();
obj.add("key1", "value1");
boolean exists = obj.contains("key1"); // true
boolean empty = obj.isEmpty(); // false
int count = obj.size(); // 1
List<String> keys = obj.names(); // ["key1"]
方法列表:
contains(String name)- 检查键是否存在isEmpty()- 检查是否为空对象size()- 获取键值对数量names()- 获取所有键名列表
# UI 组件快捷方法
JSONObject 提供了将 UI 组件数据写入 JSON 的便捷方法,这些方法使用组件的 ID 作为 JSON 的键名。
JSONObject data = new JSONObject();
// 保存 UI 组件数据到 JSON
data.putText(editText); // 保存编辑框文本
data.putChecked(checkBox); // 保存复选框选中状态
data.putSelection(spinner); // 保存下拉框选中位置
data.putCheckedPosition(radioGroup); // 保存单选组选中位置
data.putCheckedId(radioGroup); // 保存单选组选中按钮 ID
方法列表:
putText(PluginEditText)- 将编辑框文本写入 JSONputChecked(PluginCompoundButton)- 将复合按钮选中状态写入 JSONputSelection(PluginSpinner)- 将下拉框选中位置写入 JSONputCheckedPosition(PluginRadioGroup)- 将单选组选中位置写入 JSONputCheckedId(PluginRadioGroup)- 将单选组选中按钮 ID 写入 JSON
注意:这些方法要求 UI 组件必须已设置 ID(通过 Builder 的
id()方法),否则会抛出异常。
# 序列化
JSONObject obj = new JSONObject();
obj.add("name", "MT").add("version", 3);
// 转换为最小化 JSON 字符串
String json = obj.toString();
// 结果:{"name":"MT","version":3}
// 转换为格式化的 JSON 字符串
String prettyJson = obj.toString(WriterConfig.PRETTY_PRINT);
// 结果:
// {
// "name": "MT",
// "version": 3
// }
// 写入到 Writer
Writer writer = new FileWriter("config.json");
obj.writeTo(writer, WriterConfig.PRETTY_PRINT);
writer.close();
方法列表:
toString()- 转换为最小化 JSON 字符串toString(WriterConfig)- 使用指定配置转换为 JSON 字符串writeTo(Writer)- 写入到 Writer(最小化格式)writeTo(Writer, WriterConfig)- 使用指定配置写入到 Writer
# JSONArray
JSONArray 表示一个 JSON 数组,包含一组有序的 JSON 值。
# 添加值
JSONArray arr = new JSONArray();
// 添加基本类型值
arr.add(1)
.add(2.5)
.add("text")
.add(true);
// 添加 JSON 值
arr.add(JSON.object().add("key", "value"));
arr.add(JSON.array().add(1).add(2));
方法列表:
add(JSONValue value)- 添加 JSON 值add(int/long/float/double/boolean/String value)- 添加基本类型值
# 设置值
JSONArray arr = new JSONArray();
arr.add(1).add(2).add(3);
// 替换指定索引的值
arr.set(1, 20); // 将索引 1 的值从 2 改为 20
方法列表:
set(int index, JSONValue value)- 设置指定索引的 JSON 值set(int index, int/long/float/double/boolean/String value)- 设置指定索引的基本类型值
# 获取值
JSONArray arr = new JSONArray("[1, 2.5, \"text\", true]");
// 获取 JSONValue
JSONValue value = arr.get(0);
// 获取基本类型
int num = arr.getInt(0); // 1
double decimal = arr.getDouble(1); // 2.5
String text = arr.getString(2); // "text"
boolean flag = arr.getBoolean(3); // true
// 获取嵌套对象和数组
JSONObject obj = arr.getJSONObject(4);
JSONArray nested = arr.getJSONArray(5);
方法列表:
get(int index)- 获取指定索引的 JSONValuegetBoolean(int index)- 获取布尔值getInt(int index)- 获取整数getLong(int index)- 获取长整数getFloat(int index)- 获取浮点数getDouble(int index)- 获取双精度浮点数getString(int index)- 获取字符串getJSONObject(int index)- 获取嵌套对象getJSONArray(int index)- 获取嵌套数组
# 查询和操作
JSONArray arr = new JSONArray();
arr.add(1).add(2).add(3);
boolean empty = arr.isEmpty(); // false
int length = arr.size(); // 3
// 移除指定索引的元素
arr.remove(1); // 移除索引 1 的元素(值为 2)
方法列表:
isEmpty()- 检查是否为空数组size()- 获取数组长度remove(int index)- 移除指定索引的元素
# 序列化
JSONArray 的序列化方法与 JSONObject 相同:
JSONArray arr = new JSONArray();
arr.add(1).add(2).add(3);
// 转换为 JSON 字符串
String json = arr.toString(); // [1,2,3]
// 格式化输出
String prettyJson = arr.toString(WriterConfig.PRETTY_PRINT);
// 结果:
// [
// 1,
// 2,
// 3
// ]
# JSONValue
JSONValue 是所有 JSON 值的基类,提供类型判断和转换方法。
# 类型判断
JSONValue value = JSON.parse("42");
if (value.isNumber()) {
int num = value.asInt();
}
// 其他类型判断
boolean isObj = value.isObject(); // 是否为对象
boolean isArr = value.isArray(); // 是否为数组
boolean isStr = value.isString(); // 是否为字符串
boolean isNum = value.isNumber(); // 是否为数值
boolean isBool = value.isBoolean(); // 是否为布尔值
boolean isNull = value.isNull(); // 是否为 null
boolean isTrue = value.isTrue(); // 是否为 true
boolean isFalse = value.isFalse(); // 是否为 false
# 类型转换
JSONValue value = JSON.parse("\"Hello\"");
// 转换为具体类型
String str = value.asString(); // "Hello"
JSONObject obj = value.asObject(); // 如果不是对象则抛出异常
JSONArray arr = value.asArray(); // 如果不是数组则抛出异常
int num = value.asInt(); // 如果不是数值则抛出异常
long lng = value.asLong();
float flt = value.asFloat();
double dbl = value.asDouble();
boolean bool = value.asBoolean();
注意:如果类型转换失败(例如将字符串转换为对象),会抛出
UnsupportedOperationException异常。
# WriterConfig
WriterConfig 控制 JSON 输出的格式。
# 预定义配置
// 最小化输出(默认)
String compact = obj.toString(WriterConfig.MINIMAL);
// {"name":"MT","version":3}
// 格式化输出(带缩进和换行)
String pretty = obj.toString(WriterConfig.PRETTY_PRINT);
// {
// "name": "MT",
// "version": 3
// }
可用配置:
WriterConfig.MINIMAL- 最小化输出,无空格、无换行WriterConfig.PRETTY_PRINT- 格式化输出,带 2 个空格缩进和换行
# UI 组件数据绑定
MT JSON 库为 UI 组件提供了数据双向绑定功能,可以快速实现配置的保存和恢复。
# JSON → UI(Builder 方法)
UI 组件的 Builder 类提供了从 JSON 读取数据并配置组件的便捷方法。这些方法使用组件的 ID 作为键名从 JSON 中读取数据。
# PluginEditTextBuilder
从 JSON 读取文本内容并设置到编辑框:
JSONObject savedData = loadConfig(); // 假设从文件加载的配置
pluginUIBuilder
.addEditText("username")
.hint("请输入用户名")
.text(savedData) // 从 savedData 读取 "username" 字段
...
方法列表:
text(JSONObject data)- 从 JSON 读取文本内容text(JSONObject data, String defaultValue)- 从 JSON 读取文本内容,提供默认值
# PluginSpinnerBuilder
从 JSON 读取选中位置并设置到下拉框:
List<String> languages = Arrays.asList("简体中文", "English", "日本語");
pluginUIBuilder
.addSpinner("language")
.items(languages)
.selection(savedData) // 从 savedData 读取 "language" 字段
...
方法列表:
selection(JSONObject data)- 从 JSON 读取选中位置selection(JSONObject data, int defaultValue)- 从 JSON 读取选中位置,提供默认值
# PluginBaseCompoundButtonBuilder
从 JSON 读取选中状态并设置到复合按钮(CheckBox、Switch、RadioButton 等):
pluginUIBuilder
.addCheckBox("remember_me")
.text("记住密码")
.checked(savedData) // 从 savedData 读取 "remember_me" 字段
...
方法列表:
checked(JSONObject data)- 从 JSON 读取选中状态checked(JSONObject data, boolean defaultValue)- 从 JSON 读取选中状态,提供默认值
# PluginRadioGroupBuilder
从 JSON 读取选中项并设置到单选组:
pluginUIBuilder
.addRadioGroup(true)
.id("theme")
.children(builder -> builder
.addRadioButton("light").text("浅色主题")
.addRadioButton("dark").text("深色主题")
.addRadioButton("auto").text("自动")
)
.checkedId(savedData) // 从 savedData 读取 "theme" 字段(选中按钮的 ID)
...
方法列表:
checkedId(JSONObject data)- 从 JSON 读取选中按钮 IDcheckedId(JSONObject data, String defaultValue)- 从 JSON 读取选中按钮 ID,提供默认值checkedPosition(JSONObject data)- 从 JSON 读取选中位置(索引)checkedPosition(JSONObject data, int defaultValue)- 从 JSON 读取选中位置,提供默认值
# UI → JSON(JSONObject 方法)
JSONObject 提供了从 UI 组件提取数据并写入 JSON 的便捷方法。这些方法使用组件的 ID 作为键名。
# 工作原理
// 假设有以下 UI 组件
PluginEditText editUsername = pluginUI.requireViewById("username");
PluginCheckBox checkRemember = pluginUI.requireViewById("remember_me");
PluginSpinner spinnerLanguage = pluginUI.requireViewById("language");
// 创建 JSON 对象并保存 UI 数据
JSONObject data = new JSONObject();
data.putText(editUsername); // 使用 "username" 作为键名
data.putChecked(checkRemember); // 使用 "remember_me" 作为键名
data.putSelection(spinnerLanguage); // 使用 "language" 作为键名
// 保存到文件
saveConfig(data);
方法说明:
putText(PluginEditText editText)- 将编辑框的文本内容写入 JSONputChecked(PluginCompoundButton button)- 将复合按钮的选中状态写入 JSONputSelection(PluginSpinner spinner)- 将下拉框的选中位置写入 JSONputCheckedPosition(PluginRadioGroup group)- 将单选组的选中位置写入 JSONputCheckedId(PluginRadioGroup group)- 将单选组的选中按钮 ID 写入 JSON
重要:这些方法要求 UI 组件必须已设置 ID。如果组件没有 ID,
putText()、putChecked()等方法会调用requireId()并抛出异常。
# 使用示例
# 示例 1:解析和生成 JSON
展示基本的 JSON 解析、创建和格式化操作:
// 解析 JSON 字符串
String jsonText = "{\"name\":\"MT Manager\",\"version\":3,\"plugins\":[\"翻译\",\"编辑器\"]}";
JSONObject config = new JSONObject(jsonText);
// 访问数据
String name = config.getString("name", "");
int version = config.getInt("version", 0);
JSONArray plugins = config.getJSONArray("plugins");
// 遍历数组
for (int i = 0; i < plugins.size(); i++) {
String plugin = plugins.getString(i);
pluginContext.log("插件:" + plugin);
}
// 创建新的 JSON 对象
JSONObject newConfig = new JSONObject();
newConfig.add("name", "我的插件")
.add("version", 1)
.add("enabled", true);
// 创建嵌套对象
JSONObject settings = new JSONObject();
settings.add("theme", "dark")
.add("fontSize", 14);
newConfig.add("settings", settings);
// 创建数组
JSONArray features = new JSONArray();
features.add("功能A").add("功能B").add("功能C");
newConfig.add("features", features);
// 输出格式化的 JSON
String output = newConfig.toString(WriterConfig.PRETTY_PRINT);
pluginContext.log(output);
// {
// "name": "我的插件",
// "version": 1,
// "enabled": true,
// "settings": {
// "theme": "dark",
// "fontSize": 14
// },
// "features": [
// "功能A",
// "功能B",
// "功能C"
// ]
// }
# 示例 2:UI 数据双向绑定
展示完整的配置保存和恢复流程:
public class ConfigDialog {
private final PluginContext context;
private final PluginUI pluginUI;
private final File configFile;
public ConfigDialog(PluginContext context) {
this.context = context;
this.pluginUI = PluginUI.get(context);
this.configFile = new File(context.getFilesDir(), "config.json");
}
public void show() {
// 加载配置
JSONObject savedData = loadConfig();
// 创建对话框 UI
pluginUI.buildDialog()
.setTitle("设置")
.setView(builder -> builder
.addTextView("基本设置").textSize(16).bold()
.addEditText("username")
.id("username")
.hint("用户名")
.text(savedData) // 从 JSON 加载文本
.addEditText("email")
.id("email")
.hint("邮箱")
.inputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
.text(savedData) // 从 JSON 加载文本
.addSpace()
.addTextView("偏好设置").textSize(16).bold()
.addSpinner("language")
.id("language")
.items(Arrays.asList("简体中文", "English", "日本語"))
.selection(savedData, 0) // 从 JSON 加载选中位置,默认为 0
.addCheckBox("notifications")
.id("notifications")
.text("接收通知")
.checked(savedData, true) // 从 JSON 加载选中状态,默认为 true
.addCheckBox("auto_update")
.id("auto_update")
.text("自动更新")
.checked(savedData, false)
.addSpace()
.addTextView("主题设置").textSize(16).bold()
.addRadioGroup(true)
.id("theme")
.children(b -> b
.addRadioButton("light").text("浅色主题")
.addRadioButton("dark").text("深色主题")
.addRadioButton("auto").text("跟随系统")
)
.checkedId(savedData, "auto") // 从 JSON 加载选中 ID,默认为 "auto"
)
.setPositiveButton("{ok}", (dialog, which) -> {
// 收集 UI 数据
saveConfig(dialog);
})
.setNegativeButton("{cancel}", null)
.show();
}
private JSONObject loadConfig() {
if (!configFile.exists()) {
return new JSONObject();
}
try {
Reader reader = new FileReader(configFile);
JSONObject data = JSON.parse(reader).asObject();
reader.close();
return data;
} catch (Exception e) {
context.log("加载配置失败:" + e.getMessage());
return new JSONObject();
}
}
private void saveConfig(PluginDialog dialog) {
try {
// 创建 JSON 对象
JSONObject data = new JSONObject();
// 从 UI 组件收集数据
data.putText(dialog.requireViewById("username"));
data.putText(dialog.requireViewById("email"));
data.putSelection(dialog.requireViewById("language"));
data.putChecked(dialog.requireViewById("notifications"));
data.putChecked(dialog.requireViewById("auto_update"));
data.putCheckedId(dialog.requireViewById("theme"));
// 保存到文件
Writer writer = new FileWriter(configFile);
data.writeTo(writer, WriterConfig.PRETTY_PRINT);
writer.close();
context.showToast("保存成功");
} catch (Exception e) {
context.log("保存配置失败:" + e.getMessage());
context.showToast("保存失败");
}
}
}
# 示例 3:嵌套 JSON 数据处理
展示处理复杂嵌套 JSON 结构的方法:
// 创建嵌套的 JSON 结构
JSONObject root = new JSONObject();
// 添加基本信息
root.add("name", "示例项目")
.add("version", "1.0.0");
// 添加作者信息(嵌套对象)
JSONObject author = new JSONObject();
author.add("name", "张三")
.add("email", "zhangsan@example.com");
root.add("author", author);
// 添加依赖列表(嵌套数组)
JSONArray dependencies = new JSONArray();
dependencies.add(new JSONObject()
.add("name", "库A")
.add("version", "2.0.0"));
dependencies.add(new JSONObject()
.add("name", "库B")
.add("version", "1.5.3"));
root.add("dependencies", dependencies);
// 访问嵌套数据
String projectName = root.getString("name", "");
JSONObject authorInfo = root.getJSONObject("author");
String authorName = authorInfo.getString("name", "");
String authorEmail = authorInfo.getString("email", "");
// 遍历依赖列表
JSONArray deps = root.getJSONArray("dependencies");
for (int i = 0; i < deps.size(); i++) {
JSONObject dep = deps.getJSONObject(i);
String depName = dep.getString("name", "");
String depVersion = dep.getString("version", "");
pluginContext.log(depName + " " + depVersion);
}
// 修改嵌套数据
authorInfo.put("email", "newemail@example.com");
// 添加新的依赖
JSONObject newDep = new JSONObject();
newDep.add("name", "库C").add("version", "3.0.0");
deps.add(newDep);
// 输出完整的 JSON
String output = root.toString(WriterConfig.PRETTY_PRINT);
pluginContext.log(output);
# 注意事项
线程安全:MT JSON 库不是线程安全的。如果多个线程同时访问和修改 JSONObject 或 JSONArray,必须在外部进行同步。
UI 组件 ID 要求:使用 UI 组件快捷方法(
putText()、putChecked()等)时,必须确保组件已通过 Builder 的id()方法设置了 ID,否则会抛出异常。Builder 方法的行为:Builder 的 JSON 方法(如
text(JSONObject))不会尝试本地化转换,这与直接设置字符串值的text(String)方法不同。如果需要本地化文本,应使用{key}格式。默认值的使用:
getInt()、getString()等方法都提供了带默认值参数的重载版本。当 JSON 中不存在指定的键时,会返回默认值而不是抛出异常。类型转换异常:使用
asObject()、asArray()等类型转换方法时,如果类型不匹配会抛出UnsupportedOperationException。建议先使用isObject()、isArray()等方法进行类型检查。数组索引越界:访问 JSONArray 时,如果索引超出范围会抛出
IndexOutOfBoundsException。建议先使用size()方法检查数组长度。格式化输出的性能:
WriterConfig.PRETTY_PRINT会增加输出的体积(增加空格和换行符),仅建议在调试或需要人类可读的场景下使用。生产环境中应使用WriterConfig.MINIMAL。add() 和 put() 的选择:构建新对象时使用
add()性能更高;修改已有对象时使用put()确保不会产生重复键。
# 相关接口
- PluginEditText - 插件编辑框
- PluginEditTextBuilder - 编辑框构建器
- PluginSpinner - 插件下拉框
- PluginSpinnerBuilder - 下拉框构建器
- PluginCompoundButton - 插件复合按钮
- PluginBaseCompoundButtonBuilder - 复合按钮构建器
- PluginRadioGroup - 插件单选组
- PluginRadioGroupBuilder - 单选组构建器