[轉]關於Activity和Task的設計思路和方法

轉自 Androidres.com
activities_tasks_design_guideline

Activity和Task是Android Application Framework架構中最基礎的應用,開發者必須清楚它們的用法和一些開發技巧。本文用大量的篇幅並通過引用實例的方式一步步深入全面講解它們的基礎原理(underlying principles)和架構(mechanisms),例如:Navigation、Multitasking、activity re-use、intents和activity stack等…大部分與其相關的應用模塊。重點講解開發過程中如何更準確的體現用戶交互性的便捷和高效,同時也幫助分析Designers和Developers在開發期間所要面對的問題。

文中涉及到的實例有一部分是屬於平臺自帶的application(例如:撥號程序等),另外也有Google產品線中的一些有代表性的應用(例如:Google Map等)。建議大家親自利用Emulator或者Android-powered device測試實例中的效果,這樣可以幫助更加清晰的理解一些模塊的含義。(注意:可能會因爲硬件對於某些功能無法提供支持,所以有一些實例可能無法在你的測試機中正常瀏覽)

Space

首先需要清楚一些基礎模塊:

以上這四個模塊對於理解這篇文章非常重要,下邊就來逐一的簡單介紹其具體的含義和用法(也可以通過其鏈接直接查看官方文檔)。

Applications

任何一個Android Application基本上是由一些Activities組成,當用戶與應用程序交互時其所包含的部分Activities具有緊密的邏輯關係,或者各自獨立處理不同的響應。這些Activities捆綁在一起成爲了一個處理特定需求的Application, 並且以“.apk”作爲後綴名存在於文件系統中。Android平臺默認下的應用程序 例如:Email、Calendar、Browser、Maps、Text Message、Contacts、Camera和Dialer等都是一個個獨立的Apps。

Activities

上邊已經提到Activities是構成Applications的主要組成部分,其實可以更爲具體的理解爲Application僅僅是一個抽象的標籤,它將系統內一部分Activities關聯在一起,協同完成用戶的特定需求。安裝Application的過程也可以簡單理解爲將其所包裹的Activities導入到當前的系統中,如果系統中已經存在了相同的Activities,那麼將會自動將其關聯,而不會重複安裝相同的Activities,避免資源的浪費。Application卸載的過程也會檢查當前所關聯的Activities是否有被其它Application標籤所關聯,如果僅僅是提供當前的Application使用,那麼將會徹底被移除,相反則不做任何操作。

用戶與Application的交互行爲大部分都是通過GUI來完成,在Android平臺可以有兩種方式定義GUI,其中可以利用XML來預置靜態的GUI元素,或者在Activity類的內部動態定義GUI元素。這兩種不同的方法都是由Activity作爲驅動和響應用戶交互事件的主體。當啓動Application之後,至少需要一個包含有GUI信息的Activity實例被創建。

Activity的主體包括兩個主要部分,其中一個是Content(data),另外一個是響應用戶交互事件的行爲。列舉一個Dialer例子的截圖,其中包括四個部分:Dialer主界面、通訊錄、查看聯繫人信息和添加新聯繫人。

Dialer Activity Contacts list Contact View Add New Contact

下面列舉了更多比較有代表性的Applications和其所包含的Activities:

  • Email – activities to view folders, view list of messages, view a message, compose a message, and set up an account
  • Calendar – activities to view day, view week, view month, view agenda, edit an event, edit preferences, and view an alert
  • Camera – activities for running the camera, viewing the list of pictures, viewing a picture, cropping a picture, running the camcorder, viewing the list of movies, and viewing a movie
  • Game – one activity to play the game, typically another for setup
  • Maps – one activity to view a location on a map, a second for lists (such as turn list or friend list), and a third for details (friend location, status, photo)

Application基本上是由四個模塊組成:Activity、Service、Content Provider 和 Broadcast Receiver,其中Activity是實現應用的主體。

Activity Stack

操作應用程序時,有時需要調用多個Activities來完成需求,例如:發送郵件程序,首先是進入郵件主界面,然後啓動一個新的Activity用於填寫新郵件內容,同時可以調出聯繫人列表用於插入收件人信息等等。在這個操作過程中Android平臺有一個專門用於管理Activities堆棧的機制,其可以方便的線性記錄Activities實例,當完成某個操作時,可以通過這個導航功能返回之前的Activity(通過按操作檯的“Back”)。

每次啓動新的Activity都將被添加到Activity Stack。用戶可以方便的返回上一個Activity直到Home Screen,到達Home Screen後,將無法再繼續查看堆棧記錄(俗話說:到頭了- Androidres.com)。如果當前Task被中止(Interrupting the task),返回到系統主界面後啓動了其它操作,當希望返回到前一個Task繼續執行時,只需要再次通過主界面的Application launcher或者快捷方式啓動這個Task的Root Activity便可返回其中止時的狀態繼續執行。

相對於Views、Windows、Menus和Dialogs而言,Activity是唯一可被記錄在History stack中的數據,所以當你所設計的應用程序需要用戶由A界面進入到次一級界面B,當完成操作後需要再次返回A,那麼必須考慮將A看作爲Activity,否則將無法從歷史堆棧中返回。

Tasks

在Android平臺上可以將Task簡單的理解爲由多個Activities共同協作完成某一項應用,而不管Activities具體屬於哪個Application。通過下邊的圖示可以更清晰的理解Applications、Tasks、Activities三者之間的關係 (Androidres.com提供):

activities_tasks_guideline

Activities可以被看作爲是獨立存在於系統資源中,而且是作爲實現具體應用的主體,Task將一些Activity關聯起來實現一個更復雜的應用,單獨或者多個Tasks可以被定義爲一個Application。

通常實現一個Task都會存在一個Root Activity,但並不是所有情況都如此,通過Application launcher、Home screen 的快捷方式或者 由 “Recent Tasks”(長時間按住Home鍵) 最近使用過的Task記錄中啓動。當從一個Activity中啓動另外一個Activity時,Back鍵將作用於返回前一個Activity,與此同時新開啓的Activity將被添加到Activity Stack中。

這裏有兩個被表示爲Task的例子:

  • 發送帶有附件的郵件
  • 查看YouTube視頻,並且通過Email的方式共享給其他聯繫人。

- Interrupting the Task

這是Task一個非常重要的特性,用戶可以實時中止當前爲完成的Task,新開啓一個不同的Task,當新Task完成操作後,依然可以返回當上一次中止的Task繼續完成餘下操作。這個特性大大方便了同時運行多個Tasks,並且可以方便的在他們之間切換。這裏有兩種方式可以從當前Task跳轉爲其它Task(應用這兩種方式切換Task,都允許返回到Task最初中止前的狀態)。

  • 系統拋出一個Notification,當前Task會被終止,跳轉爲Notification的Task。
  • 用戶強制中止

當然,除了這兩種方式以外,還有另外一個特殊情況,算作爲第三種方式來啓動一個新的Task:Activity本身被定義爲一個Task。例如: Maps和Browser就是屬於第三種情況的Application,通過郵件中的一個地址來啓動Maps Activity作爲一個新的Task,或者通過郵件中的鏈接啓動Browser來啓動一個新的Task。當處在這種情況下,Back按鍵被觸發後,將返回到上一個Task(郵件),因爲這些新的Tasks並不是通過Home Screen中的Application launcher或者快捷方式來啓動。

Space

瞭解Activities和Tasks的基本原理

請大家一定首先理解之前所提及的內容,如果對某些概念依然含混不清,請及時查閱更多資料(官方文檔是最好的學習資料),否則無法快速理解接下來將要講述的例子,甚至喪失閱讀興趣。

接下來,將通過一些有代表性的實例瞭解關於Applications、Activities、Activities stack、Tasks和Intent等一些模塊的最基本原理。從各個角度分析系統對於用戶在不同模式下操作的反應原理。

從Home啓動一個Activity

絕大部分的Application都由此啓動(也有一些Application是通過其它Application啓動)。具體的方式有兩種,其一是從系統的Application Launcher啓動,另一種是直接由Home Screen的快捷方式。啓動Application後,Root Activity會顯示在當前窗口,並可直接供用戶操作界面元素。官方給出了一個有關這個過程的圖示,其實我感覺這個描述的還不夠直觀,湊合着用吧。大體的過程是由Home下啓動Email Application,在這個應用程序中可以直接提供給用戶操作的是List Messages Activity,Home Activity切換爲後臺運行。

hometaskbasics1a

應用Back或Home鍵離開當前Activity的區別

應用Back或者Home都可以離開當前Activity(基於Application的Root Activity),Home activity重新切換到foreground,然而二者最根本的區別在於用戶是否還需要保留當前Activity的state。

- Back:

將會終止(Destroy)當前正在運行的Activity,返回到之前的Activity(如果是 Root Activity,那麼將會直接返回到Home Activity)。官方給出了一個相關過程的圖示,當用戶正在操作List Messages Activity時,下拉郵件列表(改變了Scrolling狀態),通過Back鍵返回到Home Activity之後,當再次通過Email Icon啓動 List Messages Activity時,將會看到列表處在初始位置。通過這個演示可以瞭解到通過Back鍵離開當前Activity時,無法暫時保留住其State數據,當再次啓動時相當於重新創建了一個實例。

hometaskbasics1b

-Home:

利用Home取代Back返回的方式,當前Activity將被切換到Background,而不是被Destroied。這樣的好吃是可以暫時保留這個Activity的State信息,當再次通過Application launcher或者快捷方式啓動時,可以返回到最後離開的狀態。對比在Back中引用的例子,當再次由Home返回到Activity時,將會看到最後一次操作所記錄的Scroll狀態,而不是默認的初始位置。

hometaskbasics1c

Exception(例外情況)

前邊列舉了兩種典型的情況,同時還存在一些例外的情況,某些Activity從Background被“召喚”到foreground之後依然是相當於重新創建了新實例,其有區別於前邊所論述的結果。即便是暫時保存在Background模式下(沒有被Destroied),其State數據也將丟失。例如:Contacts 和 Gallery 等。當用戶啓動了Contact應用程序,並點選某個條目查看詳細信息,如果通過Home鍵返回後,再次重複啓動Contact應用程序時,看到的並不是之前所打開的特定條目的詳細信息,而是初始的默認界面。這個例子說明不是所有情況下通過Home鍵返回後都可以保存當前Activity的State信息。

另外一種是與Back鍵有關的特殊情況。前邊提及到大部分的Activity通過Back鍵返回到Home Activity時,其自身將被徹底銷燬,默認情況下Activity響應Back按鍵的方法被定義了Destroy行爲。但對於某些特別情況,開發者可以根據需求將相應Back按鍵事件的行爲重新“override”,撤消默認的Destroy行爲。音樂播放器是與其相關的一個典型應用,當用戶在播放器的Root Activity中觸發Back按鍵後,轉爲Background模式下繼續播放當前的音樂,同時Home Activity轉爲Foreground。

Activity的複用

在多個不同的Applications中,當遇到有相同目的應用時,會涉及到Activity的複用性問題,這在開發過程中是一個非常普遍的情況。複用性一直被衆多開發機構強調爲節約成本,優化資源的最有效的機制。對於移動應用平臺更加看重資源的最優化利用,複用性的應用在Android平臺上無處不在,通過兩個比較基礎的例子來具體的說明。

- Contacts利用Gallery獲得圖像資源

衆所周知Contacts是手機中最常用的應用程序,主要用於存儲當前用戶的聯繫人信息,其中需要包含聯繫人的頭像信息。在Android平臺中的圖像信息是由Gallery管理,所以Contacts必然需要複用Gallery Activity來獲取相應的圖像信息。

針對於Android或者其它平臺開發應用程序都需要有良好的複用性意識,這個需要貫穿於項目的整個開發過程。包括如何利用當前系統的現有資源,或者考慮到將來可能會被其它應用程序用於完成特定的需求。當用戶正在調用的Intent filter不唯一時,系統將彈出一個供用戶選擇的對話框,這的確是一個完美的解決方法。

reusinganactivity1

- 利用Messaging擴展Gallery共享功能

用戶通過Gallery查看當前系統中的圖像資源,每次單獨打開一幅圖像資源都可以通過Menu -> Share將當前的資源以附件形式插入新創建的Messaging中,並且以正常發送信息的方式將其共享給收件人。如果取消當前的共享行爲,只需要通過Back按鍵返回到Gallery Activity。相比較前一個例子的區別在於,Message Activity完成發送或者被取消操作,其不會返回任何信息。

reusinganactivity2

以上兩個例子分別講解了利用一系列的Activities來完成某一項需求,並且它們都調用了外部的Application資源。

Replacing an Activity

目前要介紹的內容是關於在不同的Applications中,有相同Intent filter屬性的Activities可相互間替換,這對於習慣Windows等操作系統的用戶比較不容易理解。其實如果您足夠細心,就可以發現之前的例子中有關於這裏所提及情況。

通常遇到這種情況發生時,一般都是因爲外部具有相同功能的Activity A 在處理問題的能力方面要優於當前Application中默認的操作行爲Activity B,系統會拋出一個可供選擇的對話框,用戶根據主觀判斷來選擇最優的方式處理當前任務。通過一個比較容易理解的實例來說明整個過程,建議“動手能力強”的同學可以通過模擬器親自嘗試。

例如:用戶在當前系統下加載了最新的Phone Ringtone Activity,取名爲Rings Extended。如果用戶通過Setting -> Sounds&Display -> Phone Ringtone 來設置當前的鈴音屬性時,將會彈出一個包含有系統默認的Phone Ringtone Activity 和最新加載的Rings Extended兩種可供選擇的操作應用,同時在對話框中還提供了一種可以直接啓動系統默認的操作方式選項。如果用戶選擇了Rings Extended,那麼其將會被載入當前的線程中替代原有的默認操作行爲,可以根據下面的圖示來增強理解。

replacinganactivity

多任務同時運行(Multitasking)

在之前的板塊有專門提到關於Home和Back兩種切換到Home Screen的方法和它們之間的差異性,這個章節將會重點涉及到系統可以同時處理多個實時運行的任務。如果用戶正處於某個Application A開啓狀態時,通過Home按鍵切換回Home Activity的同時保留了此前Application A運行的狀態信息,可以開啓新程序的同時,也可以再次將Application A切換回Foreground。

接下來通過一個有關Map應用的實例更加具體的瞭解其所涵蓋的過程。

首先的起始階段分爲三個步驟,

第一步,由Application Launcher啓動Map應用程序,並且搜索一個具體的地理位置。假設當前的網絡環境非常不理想,需要花費一定的時間Download地圖數據。

第二步,當系統需要花費較長時間加載當前地圖信息數據時,保持當前Activity的狀態,返回Home Activity啓動其它的Applicaton,地圖Activity切換到Background,而並不會中斷加載進度(依然保持網絡連接)。

注意:以上是Activity在默認條件下的反應行爲,其切換爲Background狀態後直接觸發onStop()事件,開發者可以重新定義其方法。例如:強制Activity在轉爲Background狀態下,終止網絡連接。

第三步,當前Map activity已經切換到Background狀態下運行,Home Activity切換到Foreground。這時用戶啓動Calender activity,其將自動轉爲Foreground狀態,同時獲得操作焦點。

將以上三個步驟用圖示的方式表述:

hometaskbasics1d

最後,退出當前Calender activity返回到Home,再次通過Maps圖標將其處在Background狀態的實例切換到Foreground。

hometaskbasics1e

通過上邊的例子看出用戶通過Application Launcher同時運行多個Tasks,代表系統具備多任務處理機制 – Running multiple tasks。

啓動Application的兩種不同方式

每個App都需要提供至少一個Entry point(翻譯成“入口點”有點彆扭,乾脆保留原樣)供用戶或者系統調用其所關聯的Activities,Application launcher中的小圖標就是每個單獨App的Entry Point。另外App也可以相互間通過Activity作爲Entry Point來啓動,可以將App所包含的每個Activity看作爲潛在的Entry point。

系統中的Phone Application同樣具有兩個Entry Points:Contacts和Dialer。下邊的圖示中可以瞭解到用戶通過Application launcher啓動Contacts Activity,選擇其中某一個聯繫人之後,調用Dialer Activity撥打其所提供的電話號碼。

phoneactivitiesdiagram

Intents

在現實世界中大家每時每刻都會與周圍的環境發生互動,這個互動的過程首先要確定一種意識,例如:感覺到口渴,需要水分補充。這種意識會引導自己以習慣的方式解決口渴問題,採用的方式可以多種多樣,吃冰淇淋、喝水、嚼樹葉等。類似於口渴的意識形態被抽象爲Intent,並將其看作是一種對象,這就是Android響應“意識”的方式。

在Android平臺上,用戶的操作行爲是由各種不同的事件組成,系統會將每個事件都抽象爲Intent對象,尋找解決這項需求的具體方法。抽象的Intent對象有兩種形式,第一種是“明確”的Intent(Explicit Intent),在初始化的時候已經爲這個Intent關聯了特定的Activity。第二種是“不明確”的Intent(Implicit Intent),代表這個Intent沒有明確關聯Activity,當它被拋出後,系統在衆多Activities中根據Intent filter來尋找與其匹配的處理方法。如果存在多個結果,用戶可以根據需要選擇合適的處理方法。

引用一個具體的例子,單擊一個mailto:[email protected]鏈接後,這個被拋出的Intent屬於 Implicit Intent ,系統抓取了解決這個Intent的結果,將所有的結果供用戶選擇(Gmail或者Email):

intentsdiagram

下邊給出更多系統默認的Intent關聯列表:

  • View the list of contacts – resolves to a contact list viewer activity
  • View a particular contact – resolves to a contact viewer activity
  • Edit a particular contact – resolves to a contact editor activity
  • Send to a particular email – resolves to an email activity
  • Dial a phone number – resolves to a phone dialer activity
  • View the list of images – resolves to an image list viewer activity
  • View a particular image – resolves to an image viewer activity
  • Crop a particular image – resolves to an image cropper activity

Intent對象包含兩個元素:

1)Action :例如 查看、編輯、撥打電話、查看圖像資源等等。

2)Data:提供給某種行爲的具體數據。加工果汁飲料,需要提供水果(黑心店除外)。

參照官網的解釋:Intent ClassIntent Filters

Tasks相互間切換

依然是應用實例來說明這個切換的過程。在這個例子中,用戶編輯一個短消息,並且插入圖像附件,但是在發送之前啓動Calendar,隨後切換回短消息編輯界面,最後發送信息。

1)啓動第一個Task:Messaging App,Home > Messaging > New Message > Menu > Attach > Picture。插入圖片的步驟需要調用Gallery Activity,它是一個獨立的外部程序。

hometaskswitching1a

hometaskswitching1b

hometaskswitching1c

接下來啓動另外一個Task,由於沒有直接從當前的Activity運行Calendar,所以需要切換到Home。

2)啓動另外一個Application(Calendar):Home > Calendar

hometaskswitching2

3)查看Calendar完成後,將Messaging由Background切換到Foreground模式,其中還包括了添加附件,並最終發送消息。

hometaskswitching3

 

至此,對於Android平臺中兩個比較核心元素: Activities和Tasks 的介紹基本告一段落,以後也許會有更多關於這方面的討論,希望得到您的關注。另外,有些朋友或許已經看過官方的原文,而本站也再次有幸得到了您的通讀,如果在某些概念或者論述內容上存在遺漏或者誤解,那麼真誠的希望能夠獲得指正和幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章