你要做的是什么
这一篇做一个匿名过程练习场:先学会”把一段过程存进变量、随时调用”,再玩它最闪亮的两个用途——后台运行 + 回调(大计算不卡界面,算完自动把结果送回来)和延时运行(3、2、1 倒计时)。
匿名过程就是不带名字的过程:像数字一样能存进变量、能塞进别的块的插槽。概念详解见过程块参考文档的匿名过程一章,看不懂没关系,动手做一遍自然就懂了。
每一关都是”搭块 → 点按钮 → 看到现象”的完整闭环。
第 0 关:准备器材
- 新建项目,命名为
匿名过程。 - 设计视图里从上到下放 6 个组件:
| 组件(调色板名) | 改名为 | 用途 | 建议属性 |
|---|---|---|---|
| 标签 | 标签1 |
第 1、2 关显示问候 | 字号 20 |
| 按钮 | 按钮_说话 |
第 1、2 关的触发 | 文本:说句话 |
| 标签 | 标签_状态 |
第 3 关显示后台状态 | 字号 20 |
| 按钮 | 按钮_开始 |
第 3 关的触发 | 文本:后台计算 |
| 标签 | 标签_倒计时 |
第 4 关显示倒数 | 字号 30 |
| 按钮 | 按钮_倒计时 |
第 4 关的触发 | 文本:倒计时 |
连上 AI 伴侣准备测试。
第 1 关:把过程存进变量
目标:点 按钮_说话,标签显示”你好!”——但你会发现我们没有创建任何命名过程,靠的是一个存在变量里的匿名过程。
搭块步骤:
- 从变量抽屉拖
初始化全局变量,命名问候。 - 从过程抽屉拖
无返回值的匿名过程(就是”to do …”形状但没有名字的那种),塞进变量。 - 匿名过程里放
设 标签1.文本 为 "你好!"。 - 从
按钮_说话抽屉拖当 按钮_说话.被点击,里面放过程抽屉的调用过程对象语句块,过程槽接取全局变量 问候。
<xml xmlns="http://www.w3.org/1999/xhtml"><block type="global_declaration" x="20" y="20"><field name="NAME">问候</field><value name="VALUE"><block type="procedures_defanonnoreturn"><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签1" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签1</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">你好!</field></block></value></block></statement></block></value></block><block type="component_event"><mutation component_type="Button" instance_name="按钮_说话" event_name="Click"></mutation><field name="COMPONENT_SELECTOR">按钮_说话</field><statement name="DO"><block type="procedures_callanonnoreturn"><value name="PROCEDURE"><block type="lexical_variable_get"><field name="VAR">global 问候</field></block></value></block></statement></block></xml>
跑通看现象:点 说句话 按钮,标签变成”你好!”。
这一关的关键理解:变量里存的不是数字,是”一段会做事的过程”。调用它,就等于把那段过程执行一遍。命名过程像”存在抽屉里的工具”,匿名过程像”拿在手里随时递给别人的纸条”。
第 2 关:给匿名过程加输入项
目标:同样点一个按钮,显示”你好,小明”——名字作为参数传进匿名过程。
搭块步骤(在第 1 关的基础上改):
- 点匿名过程左上角蓝色齿轮,把一个
输入项拖进去,改名为名字。过程块上会多出一个名字插槽。 - 把过程里的文本设置改成
合并文本("你好,", 名字)——名字从变量抽屉拖(它会出现在过程输入项里)。 - 给按钮事件里的
调用过程对象也用蓝色齿轮加上一个参数插槽,填文本小明。
<xml xmlns="http://www.w3.org/1999/xhtml"><block type="global_declaration" x="20" y="20"><field name="NAME">问候</field><value name="VALUE"><block type="procedures_defanonnoreturn"><mutation><arg name="名字"></arg></mutation><field name="VAR0">名字</field><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签1" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签1</field><field name="PROP">Text</field><value name="VALUE"><block type="text_join"><value name="ADD0"><block type="text"><field name="TEXT">你好,</field></block></value><value name="ADD1"><block type="lexical_variable_get"><field name="VAR">名字</field></block></value></block></value></block></statement></block></value></block><block type="component_event"><mutation component_type="Button" instance_name="按钮_说话" event_name="Click"></mutation><field name="COMPONENT_SELECTOR">按钮_说话</field><statement name="DO"><block type="procedures_callanonnoreturn"><mutation items="1"></mutation><value name="PROCEDURE"><block type="lexical_variable_get"><field name="VAR">global 问候</field></block></value><value name="ARG0"><block type="text"><field name="TEXT">小明</field></block></value></block></statement></block></xml>
跑通看现象:点按钮显示 你好,小明。把调用处的”小明”换成”小红”再点,问候跟着变。
对齐规则:调用块的参数个数必须和过程的输入项一样多——少了报
not enough arguments,多了报too many arguments。这是匿名过程最常见的报错。
第 3 关:后台运行 + 回调(本篇高潮)
目标:点 按钮_开始,标签先显示”正在后台计算…”,后台算完后显示”完成!结果 = …”。界面全程不卡。
在后台运行块有两个过程插槽,各司其职:
过程(后台跑):只能做计算,不能碰界面;回调过程(后台结束后自动跑):在界面线程运行,负责把结果显示出来。
搭块步骤:
- 拖
当 按钮_开始.被点击,先设 标签_状态.文本 为 "正在后台计算…"。 - 下面接控制抽屉的
在后台运行。 过程插槽放有返回值的匿名过程(”to do result”形状)。这里用控制抽屉的执行模块 & 返回结果包一条”设 全局变量 累计 为 0”,返回累计——先拿最简单的计算验证机制(想换成真计算见下面”升级”)。回调过程插槽放无返回值的匿名过程,蓝色齿轮加输入项result,里面设 标签_状态.文本 为 合并文本("完成!结果 = ", result)。
<xml xmlns="http://www.w3.org/1999/xhtml"><block type="component_event"><mutation component_type="Button" instance_name="按钮_开始" event_name="Click"></mutation><field name="COMPONENT_SELECTOR">按钮_开始</field><statement name="DO"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_状态" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_状态</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">正在后台计算…</field></block></value><next><block type="controls_run_in_background"><value name="PROCEDURE"><block type="procedures_defanonreturn"><value name="RETURN"><block type="controls_do_then_return"><statement name="STM"><block type="lexical_variable_set"><field name="VAR">global 累计</field><value name="VALUE"><block type="math_number"><field name="NUM">0</field></block></value></block></statement><value name="VALUE"><block type="lexical_variable_get"><field name="VAR">global 累计</field></block></value></block></value></block></value><value name="CALLBACK"><block type="procedures_defanonnoreturn"><mutation><arg name="result"></arg></mutation><field name="VAR0">result</field><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_状态" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_状态</field><field name="PROP">Text</field><value name="VALUE"><block type="text_join"><value name="ADD0"><block type="text"><field name="TEXT">完成!结果 = </field></block></value><value name="ADD1"><block type="lexical_variable_get"><field name="VAR">result</field></block></value></block></value></block></statement></block></value></block></next></block></statement></block></xml>
跑通看现象:点 后台计算,标签先变”正在后台计算…”,眨眼间变成”完成!结果 = 0”。0 就是后台过程返回的值——后台过程返回什么,回调的 result 就收到什么,App Inventor 自动帮你传递。
升级:把 执行模块 & 返回结果 里的语句换成真家伙,比如一个”从 1 循环到 100000000 累加”的循环(执行模块 里放 从范围循环,循环里 设 累计 为 累计 + 变量)。计算期间你会发现界面照样能点能滑——这就是后台运行的意义。
铁律:后台
过程里不要放任何设置组件属性、弹提示的块,会直接报错Can not operate views in background task。要改界面,一律写在回调过程里。
第 4 关:延时倒计时 3、2、1
目标:点 按钮_倒计时,标签依次显示 3 → 2 → 1 → 开始!,每个数字停 1 秒。
延时运行块的用法:等多少毫秒(1000 = 1 秒)之后,运行一次匿名过程。
搭块步骤:
- 拖
当 按钮_倒计时.被点击,先设 标签_倒计时.文本 为 "3"。 - 接三个
延时运行块(一条接一条往下串),毫秒分别填 1000、2000、3000,每个的匿名过程里设置一个新文本:2、1、开始!。
<xml xmlns="http://www.w3.org/1999/xhtml"><block type="component_event"><mutation component_type="Button" instance_name="按钮_倒计时" event_name="Click"></mutation><field name="COMPONENT_SELECTOR">按钮_倒计时</field><statement name="DO"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_倒计时" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_倒计时</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">3</field></block></value><next><block type="controls_run_after_period"><value name="MILLIS"><block type="math_number"><field name="NUM">1000</field></block></value><value name="PROCEDURE"><block type="procedures_defanonnoreturn"><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_倒计时" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_倒计时</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">2</field></block></value></block></statement></block></value><next><block type="controls_run_after_period"><value name="MILLIS"><block type="math_number"><field name="NUM">2000</field></block></value><value name="PROCEDURE"><block type="procedures_defanonnoreturn"><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_倒计时" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_倒计时</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">1</field></block></value></block></statement></block></value><next><block type="controls_run_after_period"><value name="MILLIS"><block type="math_number"><field name="NUM">3000</field></block></value><value name="PROCEDURE"><block type="procedures_defanonnoreturn"><statement name="STACK"><block type="component_set_get"><mutation component_type="Label" instance_name="标签_倒计时" property_name="Text" set_or_get="set" is_generic="false"></mutation><field name="COMPONENT_SELECTOR">标签_倒计时</field><field name="PROP">Text</field><value name="VALUE"><block type="text"><field name="TEXT">开始!</field></block></value></block></statement></block></value></block></next></block></next></block></next></block></statement></block></xml>
跑通看现象:点按钮,数字 3 立刻出现,1 秒后变 2,2 秒后变 1,3 秒后变成”开始!”。
为什么是 1000/2000/3000,不是三个 1000? 三个延时块是同时开始计时的——像一次定好三只闹钟:1 秒的那只先响,2 秒的其次,3 秒的最后。要是都写 1000,三只闹钟同一秒一起响,数字直接跳到”开始!”。
动动脑:想要每秒数字自动减一的”真·倒计时”,或者倒到一半能取消?用时钟组件的 计时事件 做——需要”到点自动运行”的复杂逻辑时,时钟是更灵活的选择。
排错表
| 症状 | 多半是因为 | 怎么办 |
|---|---|---|
| not enough arguments / too many arguments | 调用块的参数个数 ≠ 过程输入项个数 | 蓝色齿轮两边对齐:过程加了几个输入项,调用就给几个参数 |
| Can not operate views in background task | 后台 过程 里放了改界面的块 |
把改界面的块全部挪到 回调过程 里 |
回调里 result 显示 假 |
后台 过程 用了无返回值的匿名过程 |
换成有返回值的匿名过程,把要传的结果放在”返回”插槽 |
| 倒计时数字一次全变 | 三个延时块都写了同一个毫秒数 | 错开写 1000 / 2000 / 3000(同时起表,各自倒数) |
| 点按钮没反应 | 匿名过程存变量时塞错了槽(比如塞进了语句槽) | 初始化全局变量 的值槽只能放值块;无返回值的匿名过程恰好算一种”过程值”,能放进去 |
你已经学会了
匿名过程存进变量、带输入项调用、后台运行 + 回调传值、延时运行排闹钟——这就是”回调”思维的全部基础:把过程当作可以递来递去的东西。
下一步:
- 把第 3 关的后台计算换成你自己的大计算(比如矩阵的大表统计),回调里显示结果。
- 想看”按名称调度”“输入列表动态传参”这些进阶玩法,见过程块参考文档的常见搭配一节。
- 配套的矩阵入门案例:用矩阵管理成绩表。
扫码添加客服咨询