什么是JSON
JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式,广泛用于Web API的数据传输。几乎所有现代API接口都使用JSON格式返回数据。
一个典型的JSON数据示例:
{
"name": "Tim Beaver",
"age": 25,
"enrolled": true,
"school": {
"name": "MIT",
"city": "Cambridge"
},
"courses": ["Math", "Physics", "CS"]
}
JSON中的数据类型
| JSON类型 | 示例 | App Inventor对应类型 |
|---|---|---|
| 字符串(String) | "hello" |
文本(text) |
| 数字(Number) | 42, 3.14 |
数字(number) |
| 布尔值(Boolean) | true, false |
布尔值(boolean) |
| 数组(Array) | [1, 2, 3] |
列表(list) |
| 对象(Object) | {"key": "value"} |
字典(dictionary) |
核心要点: JSON对象({})在App Inventor中对应字典(dictionary),JSON数组([])对应列表(list)。
核心工具
在App Inventor 2中解析JSON,需要用到以下两个核心工具:
1. Web组件
Web组件用于发送HTTP请求获取API数据。它位于「连接」类别中。
关键方法:
- Get — 发送HTTP GET请求
- GotText事件 — 请求完成时触发,参数包括
responseCode(状态码)和responseContent(响应内容)
2. 字典积木块
字典积木块位于「字典」类别中,是解析JSON的核心工具。
关键积木块:
- get value for key — 通过键名获取字典中的值
- get value at key path — 通过键路径获取嵌套数据
- is a dictionary? — 判断是否为字典类型
- list by walking key path — 批量提取嵌套数据
3. JsonTextDecodeWithDictionaries方法
这是Web组件提供的方法,专门用于将JSON文本转换为App Inventor的字典/列表结构。
⚠️ 注意:请使用
JsonTextDecodeWithDictionaries而非JsonTextDecode。后者将JSON对象转换为列表对(旧版行为),前者转换为字典(推荐行为)。
解析简单JSON
假设API返回如下简单JSON:
{
"userId": 1,
"id": 1,
"title": "Hello World",
"body": "This is a test post."
}
步骤
- 使用Web组件发送GET请求
- 在GotText事件中,用
JsonTextDecodeWithDictionaries解析响应内容 - 用
get value for key提取具体字段
积木块伪代码
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
如果 responseCode = 200 则
设 变量 jsonData 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
设 变量 title 为 get value for key: "title" 从字典: jsonData
设 变量 body 为 get value for key: "body" 从字典: jsonData
设置 Label1.文本 为 title
设置 Label2.文本 为 body
否则
设置 Label1.文本 为 "请求失败,状态码:" + responseCode
要点说明
responseCode = 200表示请求成功JsonTextDecodeWithDictionaries返回一个字典对象get value for key通过键名(如"title")获取对应的值- 如果键不存在,
get value for key返回not found参数的默认值
解析嵌套JSON
实际API返回的数据往往是多层嵌套的。例如:
{
"id": 1,
"name": "Tim the Beaver",
"school": {
"name": "Massachusetts Institute of Technology",
"city": "Cambridge"
},
"enrolled": true,
"classes": ["6.001", "18.01", "8.01"]
}
这里 school 的值又是一个JSON对象(字典),classes 的值是一个JSON数组(列表)。
方法一:逐层获取
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
如果 responseCode = 200 则
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
// 第一层:获取name
设 变量 name 为 get value for key: "name" 从字典: data
// 第二层:先获取school字典,再从中获取name
设 变量 school 为 get value for key: "school" 从字典: data
设 变量 schoolName 为 get value for key: "name" 从字典: school
设置 Label1.文本 为 name
设置 Label2.文本 为 schoolName
方法二:使用 get value at key path(推荐)
get value at key path 可以通过一个路径列表一次性深入嵌套结构,更加简洁:
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
如果 responseCode = 200 则
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
// 使用键路径直接获取嵌套值
设 变量 schoolName 为 get value at key path:
生成列表("school", "name") 从字典: data
设置 Label1.文本 为 schoolName
路径 ["school", "name"] 的含义:先取 school 键的值(一个字典),再从该字典中取 name 键的值。
解析JSON数组
JSON数组在App Inventor中会被解析为列表。当JSON中包含数组时,可以用列表操作来处理。
示例数据
{
"people": [
{"first_name": "Tim", "last_name": "Beaver"},
{"first_name": "John", "last_name": "Smith"},
{"first_name": "Jane", "last_name": "Doe"}
]
}
方法一:使用 for each 循环
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
如果 responseCode = 200 则
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
设 变量 people 为 get value for key: "people" 从字典: data
设 变量 names 为 创建空列表
for each item person in 列表 people
设 变量 firstName 为 get value for key: "first_name" 从字典: person
添加 items: firstName 到列表 names
设置 Label1.文本 为 join with separator(", ", names)
// 结果显示: Tim, John, Jane
方法二:使用 list by walking key path(高级技巧)
list by walking key path 配合 walk all at level 可以一步到位:
提取所有 first_name:
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
设 变量 firstNames 为 list by walking key path:
路径: 生成列表("people", walk all at level, "first_name")
从: data
// firstNames = ["Tim", "John", "Jane"]
解释:
"people"— 进入people键,得到一个列表walk all at level— 遍历列表中的每一个元素(每个字典)"first_name"— 从每个字典中取first_name键的值
混合字典和数组的路径
如果 JSON 数据为:
{
"id": 1,
"name": "Tim the Beaver",
"classes": ["6.001", "18.01", "8.01"]
}
要获取第二门课程("18.01"),可以用数字索引:
设 变量 secondClass 为 get value at key path:
生成列表("classes", 2) 从字典: data
// secondClass = "18.01"
注意:App Inventor的列表索引从 1 开始,不是从 0 开始。
实战案例:调用天气API获取天气数据
需求描述
调用一个免费的天气API,获取指定城市的天气信息并显示。
UI设计
| 组件 | 名称 | 用途 |
|---|---|---|
| TextBox | CityTextBox | 输入城市名 |
| Button | QueryButton | 查询按钮 |
| Label | TempLabel | 显示温度 |
| Label | DescLabel | 显示天气描述 |
| Label | HumidityLabel | 显示湿度 |
| Web | Web1 | 网络请求组件 |
API说明
以 wttr.in 为例(免费天气API,无需API Key):
https://wttr.in/Beijing?format=j1
返回的JSON结构(简化版):
{
"current_condition": [
{
"temp_C": "25",
"weatherDesc": [{"value": "Sunny"}],
"humidity": "45",
"FeelsLikeC": "27"
}
],
"nearest_area": [
{
"areaName": [{"value": "Beijing"}],
"country": [{"value": "China"}]
}
]
}
完整积木块伪代码
按钮点击 — 发送请求:
当 QueryButton.被点击 时
设 变量 city 为 CityTextBox.文本
如果 city ≠ "" 则
设置 Web1.Url 为 "https://wttr.in/" + city + "?format=j1"
调用 Web1.Get()
否则
设置 TempLabel.文本 为 "请输入城市名"
接收响应 — 解析JSON:
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
如果 responseCode = 200 则
// 第一步:将JSON文本解析为字典
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
// 第二步:获取 current_condition 数组的第一个元素
设 变量 conditions 为 get value for key: "current_condition" 从字典: data
设 变量 current 为 select list item: 索引 1 从列表: conditions
// 第三步:从当前天气字典中提取各字段
设 变量 temp 为 get value for key: "temp_C" 从字典: current
设 变量 humidity 为 get value for key: "humidity" 从字典: current
设 变量 feelsLike 为 get value for key: "FeelsLikeC" 从字典: current
// 第四步:获取天气描述(嵌套更深一层)
设 变量 descList 为 get value for key: "weatherDesc" 从字典: current
设 变量 descItem 为 select list item: 索引 1 从列表: descList
设 变量 desc 为 get value for key: "value" 从字典: descItem
// 第五步:显示结果
设置 TempLabel.文本 为 "温度:" + temp + "°C(体感 " + feelsLike + "°C)"
设置 DescLabel.文本 为 "天气:" + desc
设置 HumidityLabel.文本 为 "湿度:" + humidity + "%"
否则
设置 TempLabel.文本 为 "请求失败: " + responseCode
使用 get value at key path 简化
上面的步骤二、三可以简化为:
// 直接用键路径获取温度
设 变量 temp 为 get value at key path:
生成列表("current_condition", 1, "temp_C")
从字典: data
// 直接用键路径获取湿度
设 变量 humidity 为 get value at key path:
生成列表("current_condition", 1, "humidity")
从字典: data
使用 list by walking key path 提取多个城市数据
如果返回了多个城市的数据(数组),可以批量提取:
设 变量 allTemps 为 list by walking key path:
路径: 生成列表("current_condition", walk all at level, "temp_C")
从: data
// 得到所有城市的温度列表
常用字典积木块参考
创建字典
make a dictionary:
pair: "name" → "Alice"
pair: "age" → 20
查询操作
| 积木块 | 功能 | 示例 |
|---|---|---|
get value for key |
通过键获取值 | get "name" → "Alice" |
get value at key path |
通过路径获取嵌套值 | get ["school", "name"] → "MIT" |
is key in dictionary? |
判断键是否存在 | "name" in dict? → true |
get keys |
获取所有键 | → ["name", "age"] |
get values |
获取所有值 | → ["Alice", 20] |
size of dictionary |
获取键值对数量 | → 2 |
修改操作
| 积木块 | 功能 |
|---|---|
set value for key |
设置键值(不存在则创建) |
set value for key path |
设置嵌套键值 |
delete entry for key |
删除指定键 |
类型判断
| 积木块 | 功能 |
|---|---|
is a dictionary? |
判断是否为字典 |
is a list? |
判断是否为列表 |
常见错误与解决方法
1. 使用了 JsonTextDecode 而非 JsonTextDecodeWithDictionaries
错误现象: 解析JSON对象后得到的是列表 (("key1" "value1") ("key2" "value2")) 而非字典,无法使用 get value for key。
解决方法: 始终使用 JsonTextDecodeWithDictionaries。JsonTextDecode 是旧版方法,将JSON对象转换为列表对形式(与 lookup in pairs 配合使用),不推荐用于新项目。
2. 忘记检查 responseCode
错误现象: 直接解析 responseContent,但请求可能失败(404、500等),此时 responseContent 不是有效JSON。
解决方法: 始终先判断 responseCode = 200 再解析:
当 Web1.GotText(...) 时
如果 responseCode = 200 则
// 解析JSON
否则
// 提示错误
3. 键名拼写错误
错误现象: get value for key 返回 “not found”,但JSON中确实有数据。
解决方法: 仔细核对键名,注意大小写。JSON键名是区分大小写的。"Temp_C" 和 "temp_C" 是不同的键。
4. 混淆列表和字典
错误现象: 对列表使用 get value for key 或对字典使用 select list item,导致运行时错误。
解决方法:
- JSON数组(
[])→ 列表 → 用select list item按索引访问 - JSON对象(
{})→ 字典 → 用get value for key按键名访问 - 可用
is a dictionary?和is a list?先判断类型
5. 索引越界
错误现象: 访问列表中不存在的索引(如对3个元素的列表取第4项)。
解决方法: 先用 length of list 检查列表长度,或使用 is in list 判断。
6. 中文编码问题
错误现象: 返回的中文显示为乱码。
解决方法: 使用 PostTextWithEncoding 并指定 UTF-8 编码;或在收到响应后,确保使用正确的文本编码。App Inventor默认使用UTF-8,通常不会有此问题。
7. 异步请求陷阱
错误现象: 在调用 Web1.Get() 之后立即访问全局变量,但数据还没回来。
解决方法: Web请求是异步的。所有数据操作必须在 GotText 事件中完成,不能在调用 Get() 之后立即处理数据。
// ❌ 错误示范
当 按钮.被点击 时
调用 Web1.Get()
设置 Label1.文本 为 全局变量结果 // 此时数据还没返回!
// ✅ 正确做法
当 按钮.被点击 时
调用 Web1.Get()
当 Web1.GotText(...) 时
// 在这里处理返回的数据
设置 Label1.文本 为 解析后的结果
调试技巧
1. 打印JSON原始内容
在 GotText 事件中,先将 responseContent 显示到Label或通过 Notifier 弹窗显示,确认返回了什么数据:
当 Web1.GotText( url, responseCode, responseType, responseContent ) 时
设置 DebugLabel.文本 为 responseContent
2. 检查解析后的类型
设 变量 data 为 调用 Web1.JsonTextDecodeWithDictionaries( responseContent )
如果 is a dictionary?( data ) 则
设置 DebugLabel.文本 为 "这是一个字典"
否则 如果 is a list?( data ) 则
设置 DebugLabel.文本 为 "这是一个列表"
3. 查看字典的所有键
设 变量 keys 为 get keys 从字典: data
设置 DebugLabel.文本 为 join with separator(", ", keys)
// 输出所有键名,帮助定位正确的字段
总结
| 场景 | 使用方法 |
|---|---|
| 解析JSON文本 | Web1.JsonTextDecodeWithDictionaries(jsonText) |
| 获取简单字段 | get value for key: "key名" 从字典: dict |
| 获取嵌套字段 | get value at key path: ["层级1", "层级2", ...] 从字典: dict |
| 遍历JSON数组 | for each item in list 循环 |
| 批量提取字段 | list by walking key path + walk all at level |
| 发送GET请求 | Web1.Get() |
| 发送POST请求 | Web1.PostText(jsonText) |
推荐流程: 调用API → 检查状态码 → 解析JSON → 提取数据 → 显示结果
本文参考了 MIT App Inventor官方文档 - Dictionaries 和 Using Web APIs with JSON。
© 2025 AppInventor2中文网. 本教程基于 MIT App Inventor 官方文档编写,遵循 Creative Commons Attribution-ShareAlike 4.0 International License 协议。
扫码添加客服咨询