清泛IT社区

标题: 做了个购物清单App后,我才真正搞懂App Inventor 2的变量 [打印本页]

作者: App Inventor 2     时间: 3 小时前
标题: 做了个购物清单App后,我才真正搞懂App Inventor 2的变量
做了个购物清单App后,我才真正搞懂App Inventor 2的变量

上个月教侄子学App开发,他一脸困惑:"变量不就是装东西的盒子吗?为什么我的App总是显示旧数据?"

这让我想起自己刚接触App Inventor 2时的困惑——全局变量、局部变量、初始化、取值设置,概念都听过,但真正写App时,还是会被"数据不更新""变量作用域混乱"这些问题反复折磨。

干脆用一个购物清单App的实际开发过程,把变量那点事彻底讲透。

需求分析

侄子想要一个简单的购物清单:
- 能添加商品名称和数量
- 能查看当前清单
- 能删除已购买的物品
- 关闭App再打开,数据还在

看似简单,但每一条背后都涉及变量的核心知识点。

技术方案

- 存储商品列表 → 全局变量 → 整个App共享
- 临时输入暂存 → 局部变量 → 过程内部使用
- 商品计数 → 全局变量 → 跨屏访问
- 持久化存储 → TinyDB + 全局变量 → 配合使用

关键实现

Step 1:初始化全局变量——构建数据地基

拖出一个 initialize global 积木:

initialize global shoppingList to [create empty list]
initialize global totalCount to 0


关键理解:全局变量在App启动时就被创建,所有Screen、所有过程都能访问它。这就是为什么它叫"全局"——作用域覆盖整个App。

侄子一开始犯了个经典错误:在按钮点击事件里初始化全局变量。结果每点一次按钮,列表就被清空一次。全局变量的初始化只执行一次,这是和局部变量最大的区别之一。

Step 2:局部变量——过程中的临时工

添加商品时,需要先暂存用户输入,验证后再写入列表:

when ButtonAdd.Click:
    initialize local itemName to TextBoxName.Text
    initialize local itemQty to TextBoxQty.Text
   
    if itemName != "" then:
        add items to list: global shoppingList
        set global totalCount to totalCount + 1


关键理解initialize local 创建的变量只在当前过程(Procedure)或事件(Event)内有效。执行块(do)适合执行操作,返回值块(return)适合计算后返回结果。

侄子问:"为什么不直接用 TextBoxName.Text?"

好问题。用一个局部变量 itemName 暂存,好处是:
1. 代码更清晰——名字比 TextBoxName.Text 好读
2. 性能更好——避免反复访问组件属性
3. 便于调试——一眼看到中间值

Step 3:取值与设置——变量的日常操作

查看清单时,遍历全局变量:

when ButtonView.Click:
    initialize local displayText to ""
    for each item in global shoppingList:
        set displayText to displayText & item
    set LabelDisplay.Text to displayText


这里有两个核心积木:
- get(取值):读取变量的当前值
- set(设置值):给变量赋新值

看似简单,但有个陷阱:全局变量用 set 会直接覆盖。如果你想累加,必须写成 set global X to get X + 1,而不是 set global X to 1

Step 4:持久化——变量的"存档"机制

全局变量在App关闭后就消失了。要实现"关闭再打开数据还在",需要TinyDB配合:

when Screen1.Initialize:
    set global shoppingList to TinyDB1.GetValue(tag: "shoppingList", default: create empty list)
    set global totalCount to TinyDB1.GetValue(tag: "count", default: 0)

when ButtonSave.Click:
    call TinyDB1.StoreValue(tag: "shoppingList", value: global shoppingList)
    call TinyDB1.StoreValue(tag: "count", value: global totalCount)


模式:Screen初始化时从TinyDB加载 → 运行中用全局变量操作 → 退出前存回TinyDB。

踩过的坑

坑1:局部变量在过程外访问
侄子试图在按钮B里访问按钮A中创建的局部变量。当然失败——局部变量的生命周期仅限于声明它的块内

解法:需要跨事件共享的数据,必须用全局变量。

坑2:变量命名冲突
同时用了 count 做全局变量名和局部变量名,结果全局变量的值被局部变量"遮蔽"。

解法:全局变量统一加前缀 g_(如 g_count),或用描述性名称(如 totalItemCount)。

坑3:初始化顺序
Screen.Initialize 里先用了变量,再初始化它。变量还没创建就被读取,返回空值。

解法:所有全局变量的初始化放在Screen.Initialize的最前面。

最终效果

侄子的购物清单App成功运行:
- 添加商品(局部变量暂存 + 全局列表追加)
- 查看清单(遍历全局变量 + 字符串拼接)
- 持久化(TinyDB + 全局变量配合)
- 商品计数(全局变量累加)

他在学校展示时,同学都惊讶"这么简单的积木能做出真正好用的App"。

复盘感悟

变量是编程的地基。App Inventor 2把变量简化为5种积木块——初始化全局、初始化局部(do)、初始化局部(return)、取值、设置值——看起来简单,但每个都有其使用场景:

- 全局变量:App级共享数据,初始化一次
- 局部变量(do):过程中的临时操作,用完即弃
- 局部变量(return):过程中的临时计算,返回结果
- get/set:读写变量的唯一方式

记住一个原则:能用局部变量就不用全局变量。作用域越小,出bug的概率越低。




更多App Inventor 2教程和实战案例,欢迎访问 App Inventor 2 中文网
加入我们的技术社区:清泛IT社区 -- 与更多开发者一起交流




欢迎光临 清泛IT社区 (https://bbs.tsingfun.com/) Powered by Discuz! X3.3