就像人類需要記憶一樣,應用需要存儲。本章將探究如何在應用中實現信息的存儲。
如果剛剛有人在電話里告訴你一家披薩店的電話號碼,你的大腦中會留下一段記憶;這時,如果有人大聲告訴你一串數字,并要你記住,你也會將它們保存到記憶中。在這種情況下,你未必能清楚地意識到,你的大腦是在保存或調用信息。

應用同樣具備記憶功能,但它的內在機制并不像大腦那樣神秘。本章你將學習如何設置應用的存儲功能,如何利用它來保存信息,以及之后如何提取這些信息。
## **有名稱的存儲槽**
應用的存儲功能由一組有名稱的存儲槽(memory slots)組成。一旦組件被拖到應用中,就會自動創建了一組被稱為“屬性”的存儲槽;也可以定義與特定組件無關的、有名稱的存儲槽,即變量。如果說屬性通常與應用的外觀呈現有關,那么變量則被認為是應用中不可見的“暫時”記憶。
### **屬性**
在應用中,組件,或者說像Button、TextBox以及Canvas這類可視組件,構成了完整的用戶界面。而組件本身的外觀則是又一組屬性來確定,屬性值就保存在存儲槽中。
在組件設計器中,可以直接對屬性的存儲槽進行修改,如圖16-1所示。

**圖 16-1 在屬性欄中修改存儲槽來改變應用的外觀**
圖16-1中的Canvas組件具有六個屬性:BackgroundColor及PaintColor是保存顏色的存儲槽,BackgroundImage保存了文件名(kitty.png),Visible屬性保存了一個布爾值(true或false,依賴于是否勾選了方框),而Width及Height屬性保存了一個數字或某個特定的設置(如,“Fill parent”)。
在組件設計器中設置組件的屬性,相當于設置應用啟動時的外觀。應用的最終用戶從未見過應用中有一個名字為Height、值為300的存儲槽,他們只能看見用戶界面上有一個300像素高的組件。
### **定義變量**
像屬性一樣,變量也是被命名的存儲槽,只是與特定的組件無關。在應用中,需要記住某個狀態,如果無法用組件的屬性來保存它,就需要定義一個變量來保存它。例如,一個游戲類的應用可能需要記住玩家到達的等級。如果等級數用Label組件來顯示,就不需要定義變量,因為Label組件的Text屬性可以用來保存這個等級。但是,如果等級數不需要顯示給用戶,就應該定義一個變量來保存它。
另一個使用變量的例子是第8章總統測驗。在這個應用中,用戶界面上一次只能顯示一道測驗題,而其他問題用戶是看不見的,因此,就需要定義一個問題列表的變量來保存它們。
在組件設計器中拖入一個組件,它的屬性就自動創建完成了,相比之下,變量的定義需要在塊編輯器中直接拖出一個**變量初始化塊**(initialize global name to),點擊塊中的“name”為變量命名,并為變量設置初始值,方法是拖出一個塊放入變量初始化塊中,可以是number塊、text塊、color塊或者是make a list塊。跟隨下面的步驟就可以創建一個叫做score的初始值為0的變量。
1\. 從塊編輯器的Built-in分組中找到Variables,點擊打開抽屜并拖出“initialize global name to”塊,如圖16-2所示。

**圖 16-2 拖出變量初始化塊**
2\. 為變量命名:點擊變量初始化塊中的“name”,并輸入“score”,如圖16-3所示。

**圖 16-3 為變量命名**
3\. 為變量設置初始值:從Math抽屜中拖出數字塊,將其插入變量初始化塊的插槽中,如圖16-4所示。

**圖 16-4 為變量設初始值**
4\. 將變量初始值由默認值(0)改為123,如圖16-5所示。

**圖 16-5 修改變量的初始值**
定義一個變量,就是通知應用建立一個有名稱的存儲槽,來保存某個值。像屬性一樣,這些存儲槽用戶是看不見的。
變量的初始值在應用啟動時就已經被放入存儲槽中。可以用數字或文本對變量進行初始化,除此之外,也可以插入一個“make a list”塊,它告訴應用這個變量是一個存儲槽的列表,而不是一個單獨的值。關于list的更多內容請參考第19章。
## **設置及讀取變量**
變量定義之后,App Inventor會生成兩個屬于這個變量的塊:set塊及get塊,只要將鼠標懸停在變量初始化塊中的變量名稱之上,就可以呼出到這兩個塊。如圖16-6所示。

**圖 16-6 變量初始化塊包含訪問該變量的set塊及get塊**
其中的“set global score to”塊可以用來修改(設置)變量的值,例如圖16-7中,將數字塊5放在變量score的set塊中。變量初始化塊中的“global”一詞意為“全局的”,指的是變量的適用范圍,一個全局變量可以被程序中所有事件處理程序及過程所引用。新版的App Inventor中還可以定義一種“local”變量,這種變量可以在一個事件處理程序或某個過程的內部進行定義(這里暫不涉及)。

**圖 16-7 將數字5賦給變量score**
另一個“get global score”塊用于從變量中讀取變量值。例如,如果你想檢查score的值是否大于或等于100,就可以將“get global score”塊插入if塊進行測試,如圖16-8所示。

**圖 16-8 使用get global score塊來獲取變量值**
### **用表達式為變量賦值**
可以用單一的數字5來為變量賦值,不過通常會用一個更為復雜的表達式來為變量賦值(“表達式”是一個計算機科學的術語,即公式)。例如,在總統測試的應用中,用戶點擊“下一題”按鈕時,要讓變量currentQuestionIndex的值增加1,來顯示下一道題;又如在游戲類應用中,如果玩家失敗,還有可能將他的成績減10分;還有像第3章打地鼠的游戲中,通過改變變量x的值,實現地鼠在Canvas中水平位置的隨機移動。因此可以用若干個塊組成的表達式插入“set global score”塊為變量score賦值。
### **變量的遞增**
一種最常見的表達式可能是變量的遞增,或根據變量的當前值進行設定。例如,游戲中當玩家獲勝一次,變量score就將增加5,如16-9顯示了實現這一行為需要的塊。

**圖 16-9 分數變量遞增5**
如果能夠理解這些塊的含義,你就離程序員又近了一步。這些塊可以理解為“讓成績在現有的值上加1”,這是變量遞增的另一種說法。要理解這些塊的工作機制,需要按照從內向外、而不是從左到右的順序,最里面的塊是“get global score”及數字“5”,它們是最基礎的塊,然后“+”塊執行加法運算,并將結果設定為變量score的值。
假設存儲槽中score的當前值為5,經過這些塊的運算,程序執行了以下步驟:
1\. 從score的存儲槽中讀取當前值5;
2\. 加上5得到結果10;
3\. 將10放回到score的存儲槽中(來替代5)。
關于變量遞增的更多內容請參見第19章。
### **構造復雜的表達式**
在Math抽屜中(圖16-10),App Inventor提供了許多數學函數,就像在電子表格或計算器中見到的一樣。

**圖 16-10 Math抽屜中的運算符及函數**
你可以使用這些塊來構造復雜的表達式,并將它們作為賦值表達式插入到“set global to”塊中。例如,要想實現一個圖片精靈(image sprite)在canvas范圍內的隨機水平移動,就需要使用一個乘法塊(*)、一個減法塊(-)一個Canvas.Width屬性以及一個隨機小數函數來組織表達式,如圖16-11所示。

**圖 16-11 使用數學(Math)塊來構造上面的復雜表達式**
正如在前面變量遞增的例子中所說,程序對這些塊的解釋是遵循從內而外的順序。假設Canvas的Width屬性值為300,ImageSprite的Width為50,程序將執行以下步驟:
1\. 分別從Canvas1.Width及ImageSprite.Width的存儲槽中讀取300及50;
2\. 減法運算:300 - 50 = 250;
3\. 調用隨機小數函數獲得一個1-1之間的隨機數(比如說0.5);
4\. 乘法運算:250 * 0.5 = 125;
5\. 將125放在ImageSprite.x屬性的存儲槽中。
## **顯示變量**
在前面的例子中,修改一個組件的屬性,將直接影響到用戶界面的外觀,而變量則不然,改變一個變量并不會直接影響到應用的外觀。如果你只是將變量score的值遞增,而不設法修改用戶界面的話,用戶永遠都不知道變化的存在,就像俗話說的“樹木落入森林”一般:如果沒有人知道它,怎么證明它的存在呢?
有時,當變量變化時,不希望在用戶界面上立即顯示出來,例如,在游戲中,可能會記錄某些統計結果(如失敗次數),只有游戲結束時才會顯示其結果。
與組件的屬性相比,這是使用變量來存儲數據的優勢:可以在需要的時間顯示必要的數據,也可以使應用中的計算與用戶界面分離,這樣做的結果是更易于稍后對用戶界面的修改。
例如,在游戲中,可以將成績直接保存在Label的Text屬性中,也可以保存在變量中。如果保存在Label中,得分時可以讓Label的Text屬性值遞增,用戶可以直接看到成績的變化;如果成績被保存到變量中,并用變量的遞增記錄得分,則需要另外設置塊,將變量值顯示到Label中。
盡管使用變量保存并顯示數據要多出一些步驟,但當你決定要修改應用,以不同的方式在用戶界面上顯示成績時,變量的方法讓改變很容易實現。你不必對每個顯示組件上的成績進行修改,它們不需要修改,你只需要修改那些與顯示有關的塊。
使用Label而非變量的方法,會讓應用變得難于修改,因為,比如說要用一個遞增的值來控制label的寬度(Width),每一次遞增都要執行一次對Width屬性的修改。
## **小結**
應用啟動之后,開始執行一系列的操作,并對發生的事件進行響應。在事件響應過程中,應用有時需要記住一些東西,如,游戲中每個選手的成績,或者某個對象的移動方向等。
應用可以用組件的屬性來實現存儲,但當你需要與組件無關的存儲槽時,就需要定義變量。可以將值保存到變量中,也可以從變量中讀取當前值,就像使用組件的屬性一樣。
無論是屬性值,還是變量值,對用戶來說都是不可見的。如果你想讓用戶看到保存在變量中的信息,只要添加塊,就可以用Label或其他用戶界面組件來顯示這些信息。
- 簡介
- 序言
- 前言
- 第 1 章 Hello 貓咪
- 第 2 章 油漆桶
- 第 3 章 打地鼠
- 第 4 章 開車不發短信
- 第 5 章 瓢蟲快跑
- 第 6 章 巴黎地圖旅游
- 第 7 章 安卓,我的車在哪?
- 第 8 章 總統測驗
- 第 9 章 木琴
- 第 10 章 出題及答題
- 第 11 章 廣播中心
- 第 12 章 遙控機器人
- 第 13 章 亞馬遜掌上書店
- 第 14 章 理解應用的結構
- 第 15 章 軟件工程與應用調試
- 第 16 章 應用中的存儲
- 第 17 章 創建動畫應用
- 第 18 章 程序中的決策:條件塊
- 第 19 章 數據列表編程
- 第 20 章 循環
- 第 21 章 定義過程
- 第 22 章 數據庫
- 第 23 章 傳感器
- 第 24 章 與Web API通信