- 这一课学什么
- 准备
- 第一步:界面(这一课新增)
- 第二步:数据长什么样
- 第三步:发送——先读后写
- 第四步:显示与自动刷新
- 断网怎么办
- 动手试一个局限
- 跑起来看看
- 常见问题
- 动手改一改
- 下一课
- 用到的组件
- 验证范围
第 2 课 班级留言板:填昵称写留言,全班的留言按时间倒序排在下面,每 10 秒自动刷新。
下载 MessageBoard.aia 返回联网 App 专题
这一课学什么
- 一个标签存一个列表:所有留言都放在标签
board里,每条留言是一个字典(昵称、内容、时间)。 - 先读后写:发送时不能直接用手机上显示的旧列表,要先从服务器取最新的,追加后再整体存回。
- 定时刷新:用计时器每 10 秒取一次,别人发的留言自己就出来了。

图为由最终 .aia 执行真实积木、连真实服务端生成的布局预览,不是真机截图。
准备
服务端照常运行(和第 1 课同一个就行)。下载 MessageBoard.aia 导入,填服务地址。
自己搭的话:顶部的「服务地址」卡片和积木与第 1 课完全一样,可以把第 1 课的积木拖进背包,在这个项目里取出来。
第一步:界面(这一课新增)
| 组件 | 名字 | 要设置的属性 |
|---|---|---|
| 文本输入框 | 文本输入框_昵称 | 提示:你的昵称 |
| 文本输入框 | 文本输入框_留言 | 允许多行、高度 90 |
| 按钮 | 按钮_发送、按钮_刷新 | |
| 标签 | 标签_留言标题、标签_刷新状态 | |
| 列表显示框 | 列表显示框_留言 | 布局:主文字 + 副文字(布局 1) |
| 计时器 | 计时器1 | 计时间隔 10000,先不启用 |
第二步:数据长什么样
服务器上标签 board 的值是一个列表,每一项是一条留言:
[
{"name": "小红", "text": "周五的物理作业是第几页?", "time": "01-15 16:00"},
{"name": "阿杰", "text": "第 52 页,第 3 到 6 题", "time": "01-15 16:03"}
]
网络微数据库可以直接存列表和字典,取回来还是列表和字典,不用自己拼文本。用浏览器打开服务地址,能看到它存成的 JSON 文本。
第三步:发送——先读后写
global 待发送 = ""
global 正在请求 = false
procedure 刷新() {
if not 正在请求 {
正在请求 = true
网络微数据库1.GetValue("board")
}
}
when 按钮_发送.Click() {
var 昵称 = trim(文本输入框_昵称.Text)
var 内容 = trim(文本输入框_留言.Text)
if 昵称 == "" {
底部提示条1.Show("先填昵称,大家才知道是谁说的")
} else if 内容 == "" {
底部提示条1.Show("留言不能为空")
} else if textLength(内容) > 200 {
底部提示条1.Show(join("最多 200 字,现在 ", textLength(内容), " 字"))
} else if 正在请求 {
底部提示条1.Show("正在和服务器通信,稍等一下再点发送")
} else {
微数据库1.StoreValue("nickname", 昵称)
待发送 = {"name": 昵称, "text": 内容, "time": 计时器1.FormatDateTime(计时器1.Now(), "MM-dd HH:mm")}
按钮_发送.Enabled = false
// 不能直接用手机上显示的旧列表:别人可能刚发了新留言
刷新()
}
}
when 网络微数据库1.GotValue(tagFromWebDB, valueFromWebDB) {
正在请求 = false
var 列表 = choose(islist(valueFromWebDB), valueFromWebDB, [])
if isdict(待发送) {
listAdd(列表, 待发送)
while length(列表) > 100 {
listRemove(列表, 1)
}
待发送 = ""
网络微数据库1.StoreValue("board", 列表)
}
// 最后调用第四步的「显示」过程,把列表画出来
}
when 网络微数据库1.ValueStored() {
按钮_发送.Enabled = true
文本输入框_留言.Text = ""
底部提示条1.Show("已发送")
}
为什么要绕一圈先读?设想你打开 App 时列表里有 3 条,看了一会儿,这期间小红发了第 4 条。如果你直接把手机上的 3 条加上自己的存回去,服务器上就只剩 4 条:小红那条被你覆盖了。先取最新的列表再追加,就能把小红的留言保留下来。
几个细节:
- 「已获得值时」既处理刷新,也处理发送:用全局变量
待发送是不是字典来区分这次读取是为了什么。 - 服务器上还没有
board时拿到的是空文本,用「是否为列表」判断,不是列表就当空列表。 - 只保留最近 100 条:列表越大,每次存取越慢。
正在请求防止刷新和发送同时进行,两个请求的结果会搅在一起。
中途验证:发一条留言,电脑浏览器刷新服务地址页面,board 的值里能看到这条留言的昵称、内容、时间。
第四步:显示与自动刷新
when 计时器1.Timer() {
if 微数据库1.GetValue("serviceUrl", "") != "" {
网络微数据库1.GetValue("board")
}
}
procedure 显示(列表) {
var 项 = []
for i = length(列表) to 1 step -1 {
var 条 = select(列表, i)
listAdd(项, 列表显示框_留言.CreateElement(join(dictget(条, "name", "?"), " · ", dictget(条, "time", "")), dictget(条, "text", ""), ""))
}
列表显示框_留言.Elements = 项
标签_留言标题.Text = join("③ 大家的留言(", length(列表), " 条)")
}
- 从最后一条倒着取,最新的就排在最上面。
- 「创建列表元素」生成带主文字和副文字的一行,交给列表显示框的「元素」。
- .aia 里的计时器事件调用的是第三步的「刷新」过程(带
正在请求检查),这里为了让这一段单独能看懂写成了直接请求。
中途验证:用另一台手机发一条留言,10 秒内这台手机上自己出现。
断网怎么办
global 待发送 = ""
global 正在请求 = false
when 网络微数据库1.WebServiceError(message) {
正在请求 = false
if isdict(待发送) {
待发送 = ""
按钮_发送.Enabled = true
底部提示条1.Show("发送失败,留言还在输入框里,稍后再点发送")
}
标签_刷新状态.Text = join("连不上服务器:", message)
}
发送失败时不清空输入框,用户写了半天的话不会丢,网络恢复后再点一次发送就行。
动手试一个局限
用两台手机,同一瞬间点发送(可以两个人数「1、2、3」一起点)。偶尔会发现只出现了一条:两台手机都取到了同样的旧列表,各自追加后写回,后写回的把先写回的覆盖了。
这是网络微数据库本身的局限:它只能整个标签一起读写,没有「往列表末尾追加一条」这种一步完成的操作。专题的验证里专门让两台手机的请求交错执行,确认确实会丢一条。
- 班级规模、偶尔发言也可能冲突,不能把人数少当作不会丢数据的保证;
- 人多、频繁写时,可以让每个人存自己的标签(如
board_小明),读的时候再合起来,但同一标签仍有覆盖风险;需要可靠的并发追加时,改用支持原子操作或事务的 CloudBase 等后端,见专题首页最后一节「学完以后」。
跑起来看看
- 发一条留言:输入框清空、提示「已发送」,列表最上面是自己的留言。
- 别的手机发了留言:最多 10 秒出现在列表里。
- 关掉服务端再发:提示发送失败,留言还在输入框里;重新开服务端后点发送成功。
- 关掉 App 再打开:昵称还在,自动刷新出最新留言。
常见问题
| 现象 | 原因与办法 |
|---|---|
| 发送后别人的留言没了 | 发送时直接存了手机上的旧列表,没有先读。照第三步改 |
列表里显示一串 {"name"…} |
把字典直接放进了列表显示框,要用「创建列表元素」取出昵称和内容 |
| 列表顺序反了 | 循环从 1 到长度是最旧的在上面;改成从长度到 1、步长 -1 |
| 一直不自动刷新 | 计时器没启用:.aia 在屏幕初始化时把「启用计时」设为真 |
| 偶尔少一条留言 | 两人同一瞬间发送,见「动手试一个局限」 |
| 留言多了越来越慢 | 列表太大。本课只保留最近 100 条,可以改成 50 |
动手改一改
- 点一条留言,用对话框显示完整内容(长留言在列表里会被截断)。
- 自己的留言用不同颜色或在昵称后加「(我)」。
下一课
第 3 课 点击挑战排行榜:每个人只保留最好成绩,没破纪录就不写服务器,再把成绩从高到低排出名次。
用到的组件
网络微数据库 · 微数据库 · 计时器 · 列表显示框 · 底部提示条
验证范围
最终 .aia 已通过正式编辑器载入与保存重开(0 错误)、后台导入和 Android APK 编译;连真实服务端执行积木检查 25 项(先读后写保留别人的留言、同一瞬间发送会丢一条、自动刷新、只保留 100 条、断网保留输入、重启恢复等),见验证记录。真机运行与 AI 伴侣联调尚未测试。
扫码添加客服咨询