開發(fā)Adobe AIR移動(dòng)應(yīng)用程序的考慮事項(xiàng)
舉例來說,移動(dòng)應(yīng)用程序常常是短期運(yùn)行的。它們需要一種可在較小的屏幕上使用的 UI,通常也需要能夠外擴(kuò)到平板電腦,并支持不同的屏幕方向。它們必須支持觸摸輸入,同時(shí)集成此類設(shè)備獨(dú)有的硬件和軟件設(shè)施。它們還必須考慮移動(dòng)設(shè)備的內(nèi)存和圖形模型。
這篇文章描述了 AIR 為支持移動(dòng)應(yīng)用程序開發(fā)而提供的特性和設(shè)計(jì)方法。文中介紹的特性和方法將幫助您開發(fā)可在安卓、BlackBerry Tablet OS 和 iOS 設(shè)備以及智能手機(jī)和平板電腦上運(yùn)行的應(yīng)用程序。
目錄
要求
預(yù)備知識(shí)
熟悉 Adobe AIR 和移動(dòng)設(shè)備開發(fā)的基本概念。
必須的產(chǎn)品
屏幕
在將移動(dòng)設(shè)備作為開發(fā)目標(biāo)時(shí),最先想到也是最重要的考慮事項(xiàng)就是屏幕。這種屏幕相對較小,無論是從物理方面還是從能夠顯示的像素?cái)?shù)方面來考慮都是如此。它還有著較高的密度(每英寸像素?cái)?shù)),不同的設(shè)備有著不同的密度和維度組合。移動(dòng)設(shè)備還可能采用水平或垂直方向放置。
為了跨這類多樣化的尺寸和密度正常操作,AIR 提供了對以下關(guān)鍵 API 的支持。
- Stage.stageWidth、 Stage.stageHeight :這兩個(gè)屬性在運(yùn)行時(shí)提供了實(shí)際的屏幕維度。請注意,在應(yīng)用程序進(jìn)入或退出全屏模式時(shí),或者在屏幕旋轉(zhuǎn)時(shí),這些值可能會(huì)發(fā)生變化。(后文將進(jìn)一步介紹旋轉(zhuǎn)。)
- Capabilities.screenDPI:這提供了屏幕上每英寸的像素?cái)?shù)。
通過將這些屬性提供的信息相結(jié)合,應(yīng)用程序即可為廣泛的屏幕調(diào)整器顯示——甚至可調(diào)整到在編寫應(yīng)用程序時(shí)未曾預(yù)計(jì)到的尺寸和維度。
注意: 如果您正在 AIR 上構(gòu)建桌面應(yīng)用程序,應(yīng)該注意移動(dòng)應(yīng)用程序僅有一個(gè) Stage,NativeWindow 類無法使用。無法使用表示該類可以被引用和實(shí)例化,但這樣做不會(huì)產(chǎn)生任何效果。這使得編寫能夠在兩種環(huán)境中正常運(yùn)作的共享代碼成為不可能的任務(wù)。要檢查 NativeWindow 是否可用,請查詢 NativeWindow.isSupported。
移動(dòng)應(yīng)用程序不需要支持屏幕旋轉(zhuǎn),但至少應(yīng)該考慮并非所有移動(dòng)設(shè)備的默認(rèn)設(shè)置均為垂直方向(高大于寬)的顯示。不希望支持屏幕旋轉(zhuǎn)的應(yīng)用程序可在應(yīng)用程序描述符內(nèi)將<autoOrients>設(shè)置為false ,從而選擇完全放棄。希望處理旋轉(zhuǎn)的應(yīng)用程序可以將<autoOrients> 設(shè)置為 true 來選擇采用,隨后偵聽 Stage 的 REORIENTING和REORIENT 事件。請注意,并非所有移動(dòng)平臺(tái)都會(huì)分發(fā) REORIENTING 事件,但它們均會(huì)分發(fā) REORIENT 事件。
另外有必要注意,應(yīng)用程序不需要使用內(nèi)置的自動(dòng)方向特性來處理屏幕旋轉(zhuǎn)。然而,如果您希望匹配系統(tǒng)行為,內(nèi)置的事件將是最適用的。舉例來說,在某些帶有滑出式物理鍵盤的設(shè)備上,系統(tǒng)放行將更改為與鍵盤一致,即便在設(shè)備本身實(shí)際上并未發(fā)生旋轉(zhuǎn)時(shí)也是如此。對于需要文本輸入的應(yīng)用程序,可能有必要在這種情況下重新定向。對于其他應(yīng)用程序(例如游戲),則可能需要關(guān)閉自動(dòng)方向調(diào)整,轉(zhuǎn)為監(jiān)視加速計(jì)事件來確定設(shè)備的物理方向。我將在本文稍后的內(nèi)容中介紹加速計(jì)。
觸摸輸入
在應(yīng)用程序顯示到屏幕上之后,通常就準(zhǔn)備好了接受用戶的某些輸入。對于移動(dòng)應(yīng)用程序來說,這就意味著接受觸摸輸入。
AIR 可自動(dòng)將簡單的單指手勢(例如單指輕敲按鈕)映射到對應(yīng)的鼠標(biāo)事件。這使得編寫能夠以合情合理的方式在移動(dòng)平臺(tái)和桌面平臺(tái)中運(yùn)行的共享代碼成為可能。
對于更加復(fù)雜的交互,您需要利用多點(diǎn)觸控輸入。面向移動(dòng)的 AIR 通過支持以下關(guān)鍵 API 提供了多點(diǎn)觸控支持:
- Multitouch:這個(gè)控制器類允許應(yīng)用程序確定有哪些觸摸事件和手勢事件可用,并選擇要使用的事件。
- TouchEvent:在處理原始觸摸事件時(shí),應(yīng)用程序?qū)⒔邮盏竭@種類型的事件。
- GestureEvent, PressAndTapGestureEvent, TransformGestureEvent:在處理手勢時(shí),應(yīng)用程序?qū)⒔邮盏竭@些事件。
對于處理基礎(chǔ)平臺(tái)的標(biāo)準(zhǔn)手勢事件(例如,收攏或張開兩根手指以便放大或縮小)的應(yīng)用程序來說,應(yīng)將 Multitouch.inputMode 設(shè)置為MultitouchInputMode.GESTURE。系統(tǒng)可將多個(gè)觸摸點(diǎn)綜合成手勢,并為各手勢提供手勢事件。舉例來說,一個(gè)放大手勢將分派為類型是TransformGestureEvent.GESTURE_ZOOM的TransformGestureEvent。
應(yīng)用程序還可選擇接受原始觸摸事件,方法是將Multitouch.inputMode 設(shè)置為MultitouchInputMode.TOUCH_POINT。系統(tǒng)將為每次觸摸分派一系列事件,表示觸摸點(diǎn)從何時(shí)開始,如何逐漸移動(dòng),以及在何時(shí)結(jié)束。除此之外,多個(gè)觸摸點(diǎn)可以同時(shí)發(fā)生。應(yīng)用程序負(fù)責(zé)將這種事件流綜合成為一些有意義的內(nèi)容。
文本輸入
此外還需要特別考慮帶有軟鍵盤(顯示在屏幕上的鍵盤,無物理按鍵)的移動(dòng)設(shè)備。盡管并非所有移動(dòng)設(shè)備都使用軟鍵盤,但此類設(shè)備已經(jīng)日益普及化,因此您應(yīng)確保應(yīng)用程序能夠很好地在配備軟鍵盤的設(shè)備中工作。
在可見情況下,軟鍵盤無疑要占用一定的可用屏幕空間。為了適應(yīng)這種情況,AIR 默認(rèn)將調(diào)整 Stage,使得文本輸入控件和鍵盤同時(shí)保持可見。在這種情況下,Stage 的調(diào)整通常是上推,因此,Stage 的最上端將被屏幕上端截?cái)啵瑹o法看到。
應(yīng)用程序可以禁用這種行為,實(shí)現(xiàn)自己的邏輯來支持軟鍵盤。這種行為由應(yīng)用程序描述符中的softKeyboardBehavior 設(shè)置控制。默認(rèn)設(shè)置為 pan。要實(shí)現(xiàn)您自己的邏輯,請使用none。
如果默認(rèn)調(diào)整行為被禁用,軟鍵盤被激活或取消激活,則 AIR 將通過Stage.softKeyboardRect報(bào)告 Stage 中被鍵盤覆蓋的區(qū)域。應(yīng)用程序應(yīng)監(jiān)聽在此值更改時(shí)得到通知的SoftKeyboardEvent,隨后相應(yīng)地調(diào)整其布局。(將同時(shí)為這些軟鍵盤行為分派 SoftKeyboardEvent。)
應(yīng)用程序通常不需要為激活軟鍵盤而擔(dān)心,因?yàn)槲谋咀侄潍@得焦點(diǎn)時(shí)將自動(dòng)激活軟鍵盤。應(yīng)用程序還可以設(shè)置 InteractiveObject.needsSoftKeyboard,請求為任何可獲得焦點(diǎn)的交互式對象顯示軟鍵盤,并通過InteractiveObject.requestSoftKeyboard()要求立即顯示鍵盤。這些 API 對于未使用軟鍵盤的設(shè)備不會(huì)產(chǎn)生任何效果。
傳感器
移動(dòng)設(shè)備用戶通常不適應(yīng)使用多點(diǎn)觸控屏幕與其移動(dòng)應(yīng)用程序交互——他們也希望應(yīng)用程序能夠了解位置,并根據(jù)設(shè)備的物理方向和運(yùn)動(dòng)情況作出反應(yīng)。AIR 通過兩個(gè)關(guān)鍵 API 對此提供了支持:
- Geolocation:這個(gè) API 會(huì)分派事件來提供設(shè)備的地址位置(經(jīng)度和緯度)以及運(yùn)動(dòng)情況(移動(dòng)方向、速度)。
- Accelerometer:這個(gè) API 會(huì)分派事件,報(bào)告當(dāng)前沿 x、y和z 軸施加給設(shè)備的力量。
對于某些應(yīng)用程序來說,地理位置是應(yīng)用程序操作所固有的特點(diǎn)。例如,一個(gè)能過發(fā)現(xiàn)最近的 ATM 的應(yīng)用程序。更多應(yīng)用程序可利用此信息來加強(qiáng)用戶體驗(yàn)。舉例來說,一個(gè)語音備忘錄應(yīng)用程序可以記錄您記錄各備忘錄的位置,以便在回放時(shí)提供更多的上下文。
正如前文所述,如果您希望了解設(shè)備的實(shí)際方向而不僅僅是它的邏輯方向,那么加速計(jì)輸入可能會(huì)非常有用。加速計(jì)數(shù)據(jù)也能將設(shè)備本身轉(zhuǎn)為一個(gè)控制器。許多應(yīng)用程序都利用了這一點(diǎn),通過設(shè)備的傾斜或旋轉(zhuǎn)來控制應(yīng)用程序本身。
所有這些傳感器 API 都允許調(diào)用程序設(shè)置所要求的更新間隔,也就是說,位置和加速度的更新將以所要求的這個(gè)頻率分派給任何監(jiān)聽程序。請注意,任何一種方法都不能保證這樣的更新頻率。實(shí)際更新頻率將取決于多種因素,包括基礎(chǔ)硬件在內(nèi)。
WEB 視圖
如果沒有 HTML 內(nèi)容支持,任何現(xiàn)代應(yīng)用程序運(yùn)行時(shí)都是不完整的,面向移動(dòng)的 AIR 通過 StageWebView API 提供了這樣的支持。StageWebView 為 AIR 應(yīng)用程序提供了一種訪問目標(biāo)平臺(tái)的基礎(chǔ)、內(nèi)置 HTML 呈現(xiàn)功能的方法。請注意,由于 StageWebView 使用平臺(tái) HTML 控制,因此不能保證在各個(gè)平臺(tái)之間實(shí)現(xiàn)一致的呈現(xiàn)。它能保證的是在與之運(yùn)行的平臺(tái)一致的平臺(tái)上呈現(xiàn)一致的內(nèi)容。如果您正在使用它來托管 Web 頁面,這很可能會(huì)滿足您的用戶的期待。
由于依靠本機(jī)平臺(tái)控制,因此 StageWebView 并未集成顯示列表。而是浮于所有其他內(nèi)容的表面。可將其視為直接附加到 Stage——正如其名稱所示。StageWebView 控件的內(nèi)容可通過drawViewPortToBitmapData() 捕捉為位圖,可放置在顯示列表中。這可用于支持 Web 頁面的快照參與屏幕過渡動(dòng)畫(舉例來說)。
對于熟悉 AIR 中的 HTMLLoader API 用戶來說,有必要注意,StageWebView 不是適當(dāng)?shù)奶娲桨浮TMLLoader 包含內(nèi)置的 HTML 呈現(xiàn)功能,支持托管在應(yīng)用程序包含的瀏覽器沙箱以外運(yùn)行的托管 HTML 和 JavaScript。StageWebView 只能托管在傳統(tǒng)瀏覽器沙箱內(nèi)運(yùn)行的 HTML 和 JavaScript 內(nèi)容,它不能托管應(yīng)用程序本身。
如果您的用戶希望轉(zhuǎn)到瀏覽器,您可以調(diào)用 navigateToURL() 來啟用它。如果對該應(yīng)用程序注冊的 URL 前綴調(diào)用,那么這也會(huì)將用戶重定向到其他應(yīng)用程序,例如 YouTube 或 Google Maps。
圖像
在拍照方面,當(dāng)今的移動(dòng)設(shè)備的問題并非是否有攝像頭,而是有多少個(gè)攝像頭。針對移動(dòng)的 AIR 包括的全新 API,提供了與攝像頭以及設(shè)備內(nèi)已經(jīng)存儲(chǔ)的任何照片的集成。
CameraUI 和 CameraRoll 類
內(nèi)置攝像頭功能可通過全新的 CameraUI 類訪問。正如其名稱所展示的那樣,它與您熟悉的 Camera 類不同,區(qū)別在于這是一種攝像頭用戶界面的 API,而并不是攝像頭的直接 API。根據(jù)設(shè)備的不同,這就意味著用戶可能具備在靜態(tài)拍照與視頻錄制之間選擇的能力,同時(shí)也能選擇不同的分辨率、開關(guān)閃光燈、選擇前攝像頭和后攝像頭等。
移動(dòng)設(shè)備不僅可以拍照,還會(huì)存儲(chǔ)照片。用戶已拍攝圖片的庫可通過 CameraRoll 類訪問。browseForImage() 方法可用于打開設(shè)備的標(biāo)準(zhǔn) UI,以便從庫中選擇照片。相冊同樣可以寫入:圖片可通過 addBitmapData() 方法存儲(chǔ)到庫中。
MediaPromise 類
CameraUI 和 CameraRoll 均通過一種稱為 MediaEvent 的新事件類型返回選定的圖片。MediaEvent 極為簡單,只是為其 Event 父類添加了另外一個(gè)有趣的成員:data。data 成員的類型是 MediaPromise,必須通過此類訪問圖片數(shù)據(jù)。
正如其名稱所示,MediaPromise 是提供與一個(gè)媒體項(xiàng)相關(guān)的數(shù)據(jù)的承諾,例如圖片。但它并不一定存儲(chǔ)這些字節(jié)。這樣的差別是非常重要的,值得花幾分鐘來研究這種 API,以便理解如何有效地利用它。
最好在內(nèi)存中保存媒體項(xiàng),還是在存儲(chǔ)中保存媒體項(xiàng)取決于多種因素。舉例來說,對于視頻,通常必須將其保存在存儲(chǔ)中,因?yàn)榭捎脙?nèi)存往往過小;如果媒體項(xiàng)位于設(shè)備的相冊庫中,則表示其已經(jīng)處于存儲(chǔ)之中,除非有必要,否則不應(yīng)將其讀入內(nèi)存。另一方面,一張剛剛拍攝的靜止的照片通常存儲(chǔ)在內(nèi)存中,因?yàn)樗芸赡茏銐蛐。铱赡芤⒓达@示。
MediaPromise 類在單獨(dú)一個(gè)謹(jǐn)慎使用即可有效利用的對象中容納了這樣的不確定性。如果應(yīng)用程序希望在存儲(chǔ)中保存媒體項(xiàng)以便釋放內(nèi)存空間,那么可以檢查 MediaPromise.file 中是否存在非空值,從而輕松檢查該項(xiàng)是否已經(jīng)位于存儲(chǔ)之中。在處理視頻時(shí),這可能成為擁有足夠的存儲(chǔ)或者耗盡存儲(chǔ)的區(qū)別。
如果應(yīng)用程序希望在內(nèi)存中處理媒體項(xiàng),那么它將始終可通過以MediaPromise.open()訪問的流讀取。根據(jù)項(xiàng)的位置,MediaPromise 將從內(nèi)存中的副本或者存儲(chǔ)中自動(dòng)返回這些字節(jié)。在使用 open()時(shí),應(yīng)該確保檢查MediaPromise.isAsync,以便確定已經(jīng)返回的流的類型。
最后,要處理所返回的媒體項(xiàng)將添加到現(xiàn)實(shí)列表中的常見情況,可使用一種名為Loader.loadFilePromise() 的新方法擴(kuò)展 Loader 類。這允許將項(xiàng)直接添加到現(xiàn)實(shí)列表中,優(yōu)化了應(yīng)用程序節(jié)點(diǎn)中任何可能不必要的副本。正如方法的名稱所表示的那樣,這種方法可與任何 FilePromise 配合使用。MediaPromise 類實(shí)現(xiàn)了 IFilePromise 接口。
應(yīng)用程序生命周期
在移動(dòng)設(shè)備上,應(yīng)用程序具有一個(gè)幾乎無法由自己控制的生命周期。它們無法自行啟動(dòng),但可以由用戶直接啟動(dòng)(例如,在從主屏幕上啟動(dòng)時(shí)),或者由用戶簡介啟動(dòng)(例如,通過注冊的 URL 模式)。它們可以隨時(shí)發(fā)送到后臺(tái)。在后臺(tái)運(yùn)行時(shí),它們也可隨時(shí)停止,這通常是在設(shè)備中的資源不足以供前臺(tái)應(yīng)用程序使用時(shí)發(fā)生的。
移動(dòng)應(yīng)用程序無法自行啟動(dòng)或者關(guān)閉。在某些移動(dòng)平臺(tái)上,NativeApplication.exit() 是不能操作的("無作業(yè)")。應(yīng)用程序不應(yīng)依靠在關(guān)閉過程中保存狀態(tài),而是應(yīng)該在發(fā)送到后臺(tái)時(shí)和/或在運(yùn)行時(shí)定期地保存狀態(tài)。
在通過分派 DEACTIVATE 事件發(fā)送到后臺(tái)時(shí),以及相應(yīng)地通過分派 ACTIVATE 事件轉(zhuǎn)至前臺(tái)時(shí),應(yīng)用程序應(yīng)該得到通知。在應(yīng)用程序過渡到后臺(tái)和前臺(tái)時(shí),AIR 也會(huì)采取一些特定操作。具體情況依平臺(tái)的不同而有所不同。
安卓后臺(tái)行為
在安卓平臺(tái)上,應(yīng)用程序被鼓勵(lì)執(zhí)行盡可能少的后臺(tái)操作,但并未施加服務(wù)器約束。如果安卓平臺(tái)上的一個(gè) AIR 應(yīng)用程序發(fā)送到后臺(tái),則其動(dòng)畫幀速率將減至每秒四幀,盡管所有事件都將繼續(xù)分派,但事件循環(huán)的呈現(xiàn)階段將被跳過。
因此,安卓平臺(tái)上的 AIR 應(yīng)用程序可以繼續(xù)執(zhí)行后臺(tái)任務(wù),例如完成一次上傳或者下載操作,或者定期同步信息。然而,在后臺(tái)運(yùn)行時(shí),應(yīng)用程序應(yīng)該采取措施來進(jìn)一步降低其幀速率,關(guān)閉或減少其他計(jì)時(shí)器等等。
iOS 后臺(tái)行為
在 iOS 上,應(yīng)用程序不允許像通常那樣在后臺(tái)運(yùn)行,而是必須聲明它們希望執(zhí)行某種類型的后臺(tái)處理,例如保持一次 IP 語音通話繼續(xù),或者完成一次未完成的上傳。
AIR 不支持這種 iOS 后臺(tái)處理模型,因此在發(fā)送到后臺(tái)時(shí),AIR 應(yīng)用程序?qū)⒅苯訒和!F鋷俾蕦⒔档蜑榱悖粫?huì)分派任何事件,也不會(huì)呈現(xiàn)任何內(nèi)容。然而,它們默認(rèn)將主流在內(nèi)存中。這允許應(yīng)用程序在轉(zhuǎn)回前臺(tái)時(shí)保留其狀態(tài)。
性能
要在移動(dòng)應(yīng)用程序中實(shí)現(xiàn)出色的性能,首先最好為應(yīng)用程序的各個(gè)方面選擇一種可靠的基本方法。嘗試為線性時(shí)間算法實(shí)現(xiàn) 10% 的改進(jìn)所獲得的成果顯然無法與在合理位置使用常量時(shí)間算法所能夠獲得的成果相提并論。
啟動(dòng)時(shí)間
啟動(dòng)時(shí)間極具挑戰(zhàn)性,因?yàn)槠涑杀就鶗?huì)波及整個(gè)應(yīng)用程序。為了將啟動(dòng)成本保持在最低限度,應(yīng)重點(diǎn)關(guān)注運(yùn)行盡可能少的代碼,而不是提高代碼的運(yùn)行速度。
舉例來說,假設(shè)您正在編寫一款游戲,在第一個(gè)屏幕上,您希望顯示當(dāng)前的最高得分,這些信息是在本地保存的。執(zhí)行這些代碼來檢索這些得分可能會(huì)帶來令人意外的高昂成本。因?yàn)檫@是代碼路徑首次運(yùn)行,您可能需要付出解釋或編譯代碼的成本,因此它的速度將慢于穩(wěn)定狀態(tài)的 ActionScript 性能。第二,您要等待從文件系統(tǒng)中檢索信息。最后,您要付出在屏幕上排版和呈現(xiàn)信息的成本。
您應(yīng)考慮推遲所有這些工作,直至顯示第一個(gè)屏幕之后。隨后,在用戶專心欣賞您的藝術(shù)作品時(shí),即可準(zhǔn)備最高得分列表。最后,您可以通過淡入或者動(dòng)畫效果將其顯示在屏幕上。
請注意,這里的優(yōu)化模式涉及選擇何時(shí)執(zhí)行工作,而不是盡快執(zhí)行工作。這里最重要的是用戶所感受到的性能:用戶只有在等待工作完成時(shí)才會(huì)注意到這些事情。
呈現(xiàn)
GPU 的興起已經(jīng)徹底顛覆了典型呈現(xiàn)管道的性能特征。在 CPU 上呈現(xiàn)時(shí),每個(gè)像素都有著較高的成本。因此最好通過描述形狀來進(jìn)行呈現(xiàn),同時(shí)執(zhí)行預(yù)處理,使得屏幕上的每個(gè)像素僅繪制一次。這是 AIR 在呈現(xiàn)傳統(tǒng)基于矢量的內(nèi)容時(shí)所采用的基本方法。
另一方面,GPU 對于形狀的呈現(xiàn)不佳,但能夠輕松四處移動(dòng)海量像素——所移動(dòng)的像素?cái)?shù)量往往超過實(shí)際適合顯示在屏幕上的像素?cái)?shù)量幾倍之多。利用 GPU 的最佳方法就是通過一組位圖構(gòu)成 UI,隨后僅限于轉(zhuǎn)變這些位圖。
AIR 集兩者之所長。您可以利用 AIR 呈現(xiàn)模型的完整功能來進(jìn)行繪制,隨后將結(jié)果作為位圖緩存,位圖可有效地呈現(xiàn)到屏幕上。利用BitmapData.draw() 即可通過這種方式捕捉您呈現(xiàn)的結(jié)果。
請注意,也可將這些位圖與您的應(yīng)用程序打包在一起,而不是動(dòng)態(tài)呈現(xiàn)它們,屏幕大小和密度的增加使得預(yù)先生成所有必要的變體成為不可能完成的任務(wù)。因此這種方法不僅高速,還能很好地適應(yīng)當(dāng)今的設(shè)備擴(kuò)張。
內(nèi)存
盡管當(dāng)今的移動(dòng)設(shè)備包含大量的 RAM,但有必要牢記,它們所使用的內(nèi)存管理模型與傳統(tǒng)桌面操作系統(tǒng)不同。在桌面上,如果內(nèi)存需求過高,則內(nèi)存的內(nèi)容可溢出到磁盤中,稍后再返回內(nèi)存。這使操作系統(tǒng)能夠保持幾乎無數(shù)的程序同時(shí)運(yùn)行。
在移動(dòng)設(shè)備上,這種溢出到磁盤的方法不可用。反之,如果內(nèi)存需求超出了物理可用內(nèi)存,則后臺(tái)應(yīng)用程序?qū)⒈粡?qiáng)制退出,從而釋放其占用的內(nèi)存。如果完全無法滿足某個(gè)對于內(nèi)存的請求,則請求內(nèi)存的應(yīng)用程序本身將退出。
這里有兩個(gè)要點(diǎn)。首先,有必要大體了解您的應(yīng)用程序的總體內(nèi)存需求,以便確保不會(huì)耗盡內(nèi)存。其次,為了提高應(yīng)用程序在后臺(tái)運(yùn)行時(shí)保持駐留的機(jī)會(huì),您的應(yīng)用程序在后臺(tái)時(shí)必須使用盡可能少的內(nèi)存。
這些目標(biāo)均可通過顯式管理應(yīng)用程序的內(nèi)存來實(shí)現(xiàn)。乍聽起來,這或許有些奇怪,畢竟垃圾收集器應(yīng)該代替您完成這樣的工作。您最好將垃圾收集器視為某種為您清空垃圾的機(jī)制。然而,將無用對象丟到垃圾箱中的決定仍然由您做主。
采用顯式內(nèi)存管理方法時(shí),第一個(gè)步驟就是確保您清除了對于不再需要的對象的引用。舉例來說,假設(shè)您的應(yīng)用程序在啟動(dòng)時(shí)讀取一個(gè) XML 配置文件,隨后從這個(gè)文檔中復(fù)制一些重要的值。現(xiàn)在,在這個(gè)過程中創(chuàng)建的 XML 對象樹很有可能不再必要。然而,應(yīng)用程序也有可能保留了一個(gè)對根 XML 對象的引用,從而將整個(gè) XML 文檔納入內(nèi)存。在讀取了配置值之后,應(yīng)用程序應(yīng)將對 XML 文檔的引用設(shè)置為空,從而將這個(gè)對象置于垃圾箱中,使之可進(jìn)行垃圾收集。
在處理大量給定對象時(shí),顯式內(nèi)存管理也是非常重要的。舉例來說,對于一個(gè)加載一組圖片的應(yīng)用程序來說,如果采用了本機(jī)寫入,那么如果該組圖片數(shù)量過大,那么它總是會(huì)耗盡內(nèi)存。另外一方面,如果實(shí)現(xiàn)限制了一次可保存在內(nèi)存中的圖片數(shù)量,那么無論這組圖片的數(shù)量有多少,內(nèi)存始終不會(huì)耗盡。這可通過在加載新圖片之前釋放舊圖片來實(shí)現(xiàn),甚至可以采用更有效的方法,即在內(nèi)存中保留固定數(shù)量的對象,并通過它們來循環(huán)處理圖片。
存儲(chǔ)
移動(dòng)設(shè)備提供了本地文件系統(tǒng),應(yīng)用程序可利用這種本地文件系統(tǒng)來存儲(chǔ)首選項(xiàng)、文檔等。通常來說,應(yīng)用程序應(yīng)該假設(shè)此存儲(chǔ)即可由應(yīng)用程序本身訪問,不得與其他應(yīng)用程序共享。在所有平臺(tái)上多可以通過 File.applicationStorageDirectory 屬性訪問這個(gè)存儲(chǔ)。
安卓實(shí)現(xiàn)了一個(gè)輔助文件系統(tǒng),它通常位于可用 SD 卡內(nèi),通過"/sdcard"路徑訪問。不同于主應(yīng)用程序存儲(chǔ),這些位置可由設(shè)備上的所有應(yīng)用程序讀取和寫入。然而,應(yīng)用程序應(yīng)注意,這樣的輔助存儲(chǔ)并非始終可用,因?yàn)?SD 卡可能會(huì)被取出,即便未被取出,也可能未掛接。
移動(dòng)設(shè)備上的攝像頭日益普及,它們也提供了一種特定于相片的共享存儲(chǔ)位置。正如我在之前的"圖片"一節(jié)中所示,應(yīng)用程序通常應(yīng)該通過 CameraRoll API 訪問這樣的位置。盡管在某些平臺(tái)上,已存儲(chǔ)的相片可通過文件系統(tǒng) API 直接訪問,但這并不是一項(xiàng)適合所有平臺(tái)的實(shí)踐。
部署
在移動(dòng)領(lǐng)域中,部署主要是通過應(yīng)用市場完成的。這些市場中包括設(shè)備上的發(fā)現(xiàn)、安裝和更新功能。
為了準(zhǔn)備 AIR 應(yīng)用程序以便部署到特定市場,應(yīng)將其打包為恰當(dāng)?shù)奶囟ㄓ谄脚_(tái)的格式。舉例來說,要將您的應(yīng)用程序上傳到 Apple App Store,您應(yīng)將應(yīng)用程序打包為 .ipa 文件;要將其上傳到安卓市場,則應(yīng)將其打包為 .apk 文件。這些選項(xiàng)在 Flash Builder 內(nèi)即可找到,也可通過 ADT 命令行工具編寫腳本實(shí)現(xiàn)。
所有移動(dòng)應(yīng)用市場都要求發(fā)布到其中的應(yīng)用程序進(jìn)行簽名。對于 iOS,簽名必須使用 Apple 發(fā)行的證書 完成。對于安卓設(shè)備,開發(fā)人員應(yīng)該 創(chuàng)建一個(gè)有效期至少為 25 年的自簽名證書,并且必須使用相同的證書為其應(yīng)用程序的所有更新簽名。由于有著不同的證書要求,因此要對多個(gè)市場發(fā)布,就需要 跟蹤多種證書。
在您準(zhǔn)備將一個(gè)移動(dòng)應(yīng)用程序部署到安卓市場時(shí),務(wù)必牢記 AIR 本身是獨(dú)立部署的。(在 iOS 上,各應(yīng)用程序均打包了一份 AIR 副本,因此本討論不適用。)如果您的應(yīng)用程序要安裝在一個(gè)尚未安裝 AIR 的設(shè)備上,那么在應(yīng)用程序初次啟動(dòng)時(shí),用戶將被重定向,以便安裝 AIR。您應(yīng)該盡可能地確保這種重定向會(huì)將用戶返回其購買您的應(yīng)用程序時(shí)所使用的市場。為此,您可以在調(diào)用 ADT 命令行工具時(shí)通過 -airDownloadURL 標(biāo)記傳遞針對該市場的恰當(dāng) URL。如需確定應(yīng)使用的正確的 URL,請與應(yīng)用市場聯(lián)系。
關(guān)于作者
自 Adobe AIR 誕生并發(fā)展出新穎的安裝技術(shù)以來,Oliver 一直致力于這個(gè)領(lǐng)域。在轉(zhuǎn)向 AIR 之前,他致力于 Adobe LiveCycle,而在加入 Adobe 之前,他從事的領(lǐng)域很廣,包括金融服務(wù)、數(shù)字信號(hào)處理和視頻游戲。他有時(shí)為 Dr. Dobb's Journal 撰稿,并且是 Kidos Computer 技術(shù)咨詢委員會(huì)的成員。他獲得了斯坦福大學(xué)的計(jì)算機(jī)本科及碩士學(xué)位。