編輯:Android開發實例
前面介紹了Windows環境下,基於Android SDK(2.3) 和 Eclipse(helios)的Android開發環境的搭建,並創建了第一個應用程序Hello Android World。
現在,我們已經可以使用Eclipse來創建和開發Android應用程序,本文將仍以Hello Android World工程來深入解析Eclipse中Android工程的結構以及調試。
寫上篇的時候,剛好Android SDK Platform Honeycomb Preview, revision 1(android-3.0_pre_r01-linux.zip)已經加入http://dl-ssl.google.com/android/repository/repository.xml,卻無法下載,因此我們的第一個Android應用程序是用的Android SDK Platform 2.3.1,即Android 9 AVD進行演示。現在Android SDK Platform Honeycomb Preview已經放到http://dl-ssl.google.com/android/repository/android-3.0_pre_r01-linux.zip,敢為天下先是我等求知若渴的程序員的優秀品質,因此,本次我們使用最新版本的Android SDK Platform Honeycomb Preview來進行我們本次教程。
先看看最新的Honeycomb Preview的樣子吧(由於是Preview版本,啟動確實不敢恭維,根據傳聞,前幾天之所以該版本一度無法下載安裝是因為google發現這個Preview版本太爛,面子上掛不住,所以又撤掉了,呵呵):
相比手機上目前使用的最高Android 2.3版本而言,Android 3.0 Honeycomb更適合平板電腦使用,是專門為Android平板電腦進行優化的系統版本。隨著SDK的發布,更加有利於開發者和廠商針對 Android 3.0 Honeycomb平板電腦進行開發,包括Android平板電腦應用和匹配。
一、 Android 應用程序概述
1. Android的嫡系組件
Android有四項一等公民(或稱為嫡系組件),包括:Activity(活動)、ContentProvider(內容提供程序)、BroadcastReceiver(廣播接收器)與Service(服務)。它們都必須宣告於AndroidManifest.xml檔案裡。
Activity活動
活動是最常用的 Android 應用程序形式。活動在一個稱為視圖(後文將介紹)的類的幫助下,為應用程序提供 UI。視圖類實現各種 UI 元素,比如文本框、標簽、按鈕和計算平台上常見的其他 UI 元素。
一個應用程序可以包含一個或多個活動。這些活動通常與應用程序中的屏幕形成一對一關系。
應用程序通過調用 startActivity() 或 startSubActivity() 方法從一個活動轉移到另一個活動。如果應用程序只需“切換”到新的活動,就應該使用前一個方法。如果需要異步的調用/響應模式,就使用後一個方法。在這兩種情況下,都需要通過方法的參數傳遞一個 intent。
由操作系統負責決定哪個活動最適合滿足指定的 intent(後文將介紹)。
對於Activity,關鍵是其生命周期的把握(後文將介紹),其次就是狀態的保存和恢復(onSaveInstanceState onRestoreInstanceState),以及Activity之間的跳轉和數據傳輸(intent)。
Activity幾乎承接著用戶對應用程序(Application)的所有操作,Activity應該有一個窗口(Window),這個窗口是可以通過不用的主題(Theme)改變樣子的。Activity應該要注意它的生命周期(Lifecycle)、設備狀態(Configuration)改變時的影響以及運行狀態和數據的保存,這個在一個應用程序是否可靠和人性化上至關重要。Activity裡還應該要申明一些許可(Permissions),以便使用Android的一些軟硬件功能,這些申明可以由代碼或者Manifest.xml給出。最後,每個Activity(的入口)一定要在Manifest當中申明。
Service服務
與其他多任務計算環境一樣,“在後台”運行著一些應用程序,它們執行各種任務。Android 把這種應用程序稱為“Service服務”。
Service是沒有界面的程序,它是所謂的服務,也叫後台程序。應該要非常注意Service的啟動(startService)和綁定(bindService)這兩種開啟Service的方法之間的關系以及Service對應的生命周期,兩種開戶Service的方法對Service 的生命周期效果是不同的。還有就是申明許可以及申明Service,也是在代碼內或者Manifest內申明。
BroadcastReceiver廣播接收器
廣播接收器是一個應用程序組件,它接收請求並處理 intent。與服務一樣,接收器在一般情況下也沒有 UI 元素。廣播接收器通常在 AndroidManifest.xml 文件中注冊。廣播接收器的類屬性是負責實現這個接收器的 Java 類。
廣播接收並不是通常所說的無線電廣播,而是指由sendBroadcast()所發送出來的意圖(Intent),即廣播在這裡的意思是意圖,BroadcastReceiver在注冊(Registe)之後可以自動監聽符合預先給定的條件的意圖,如果有則會通知此 BroadcastReceiver的持有程序。
ContentProvider內容提供程序——數據管理
內容提供程序是 Android 的數據存儲抽象機制。我們以移動設備上常見的一種數據為例:地址簿或聯系人數據庫。地址簿包含所有聯系人及其電話號碼,用戶在使用手機時可能需要使用這些數據。內容提供程序對數據存儲的訪問方法進行抽象。內容提供程序在許多方面起到數據庫服務器的作用。對數據存儲中數據的讀寫操作應該通過適當的內容提供程序傳遞,而不是直接訪問文件或數據庫。可能還有內容提供程序的 “客戶機” 和 “實現”。
ContentProvider是作保存應用程序數據和建立維持數據庫之用,以便程序重新啟動時回到以前的狀態或者保存信息。應該注意應用程序的使用權限以及SQL語言的使用,Android用的是一個輕量級的數據庫系統SQLite。
2. Android生命周期
Android 程序的生命周期是由系統控制而非程序自身直接控制,這與桌面應用程序在程序自身收到關閉請求後執行一個特定的動作(比如從 main 函數中 return)而導致進程結束的思維不同。
在Android系統中,當某個activity調用startActivity(myIntent)時,系統會在所有已經安裝的程序中尋找其intentfilter和myIntent最匹配的一個activity,啟動這個進程,並把這個intent通知給這個activity。這就是一個程序的“生”。在Android中,所有的應用程序“生來就是平等的”,所以不光Android的核心程序甚至第三方程序也可以發出一個intent來啟動另外一個程序中的一個activity。Android的這種設計非常有利於“程序部件”的重用。
Android根據其重要性在內存不足的時候移去重要性最低的進程。重要性由高到低為:
1.前台進程。這樣的進程擁有一個在屏幕上顯示並和用戶交互的activity或者它的一個IntentReciver正在運行。這樣的程序重要性最高,只有在系統內存非常低,萬不得已時才會被結束。
2.可見進程。在屏幕上顯示,但是不在前台的程序。比如一個前台進程以對話框的形式顯示在該進程前面。這樣的進程也很重要,它們只有在系統沒有足夠內存運行所有前台進程時,才會被結束。
3.服務進程。這樣的進程在後台持續運行,比如後台音樂播放、後台數據上傳下載等。這樣的進程對用戶來說一般很有用,所以只有當系統沒有足夠內存來維持所有的前台和可見進程時,才會被結束。
4.後台進程。這樣的程序擁有一個用戶不可見的activity。這樣的程序在系統內存不足時,按照LRU的順序被結束。
5.空進程。這樣的進程不包含任何活動的程序部件。系統可能隨時關閉這類進程。
從某種意義上講,垃圾收集機制把程序員從“內存管理噩夢”中解放出來,而Android的進程生命周期管理機制把用戶從“任務管理噩夢”中解放出來。Android使用Java作為應用程序API,並且結合其獨特的生命周期管理機制同時為開發者和使用者提供最大程度的便利。
Activity生命周期
Activity中常用的函數有SetContentView() findViewById() finish() startActivity(),其生命周期涉及的函數有:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
注意的是,Activity的使用需要在Manifest文件中添加相應的<Activity>,並設置其屬性和intent-filter。
Service生命周期
Service可以通過Context.startService()或Context.bindService()創建,通過Context.stopService()、Service.stopSelf()、Service.stopSelfResult()或Context.unbindService()來關閉。其生命周期涉及的函數有:
void onCreate()
void onStart(Intent intent)
void onDestroy()
其中onCreate()和onDestroy()可以被所有服務調用,無論是由Context.startService()還是Context.bindService()發起的Service。但是,onStart()只能被由startService()發起的Service調用。
如果一個Service運行其它對象綁定它,需要擴展如下callback方法:
IBinder onBind(Intent intent)
boolean onUnbind(Intent intent)
void onRebind(Intent intent)
BroadcastReceiver生命周期
只包含一個方法:void onReceive(Context curContext, Intent broadcastMsg)
包含活動的組件的BroadcastReceiver將不會被系統關閉,但是僅包含不活動的組件的進程將隨時會背系統關閉(當其它組建需要內存時)。
3. Intent簡介——Android的創新導航與觸發機制
前文介紹了Android的四項一等公民:Activity(活動)、ContentProvider(內容提供程序)、BroadcastReceiver(廣播接收器)與Service(服務)。這四種組件是獨立的,它們之間可以互相調用,協調工作,最終組成一個真正的Android應用。
在這些組件之間的通訊中,主要是由Intent協助完成的。Intent是Android應用開發裡很重要的一個元件,通過Intent可以從一個Activity來啟動另一個任意的Activity,不管是自己定義的還是系統定義的。在ActivityGroup(extends Activity)裡面,Intent的flag設置對於子Activity的啟動方式至關重要。
Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將 Intent傳遞給調用的組件,並完成組件的調用。
因此,Intent在這裡起著一個媒體中介的作用,專門提供組件互相調用的相關信息,實現調用者與被調用者之間的解耦。
Android應用程序框架的強大之處在於它將Web習慣引入到移動應用程序中。這並不意味著該平台提供了一個強大的浏覽器,也不僅限於使用 JavaScript和服務器端資源,而是涉及Android平台的工作原理以及該平台的用戶如何與移動設備交互這一核心問題。互聯網的強大之處一言以蔽之,在於一切事物通過一次單擊即可獲得。這些單擊的內容對於用戶來說就是URL(UniformResource Locator,統一資源定位符)或URI(Uniform Resource Identifier,統一資源標識符)。有效使用URI可幫助用戶方便快捷地訪問所需的日常信息。“把鏈接發給我”就說明了一切。
在移動設備上復制桌面設備體驗的平台只能吸引一小部分忠實的用戶。多級菜單、多次單擊在移動市場中通常都不被人所接受。移動應用程序對直觀易用的要求比其他任何市場中的應用程序都要高。Intent和IntentFilter將“單擊”范例引入到了Android平台移動應用程序使用和開發的核心中。
Intent結構
Intent是執行某操作的一個抽象描述,它描述了如下內容:
首先,要執行的動作(action)的一個簡要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android為我們定義了一套標准動作:
MAIN_ACTION
VIEW_ACTION
EDIT_ACTION
PICK_ACTION
GET_CONTENT_ACTION
DIAL_ACTION
CALL_ACTION
SENDTO_ACTION
ANSWER_ACTION
INSERT_ACTION
DELETE_ACTION
RUN_ACTION
LOGIN_ACTION
CLEAR_CREDENTIALS_ACTION
SYNC_ACTION
PICK_ACTIVITY_ACTION
WEB_SEARCH_ACTION
此外,我們還可以根據應用的需要,定義我們自己的動作,並可定義相應的Activity來處理我們的自定義動作。
其次,執行動作要操作的數據(data),Android中采用指向數據的一個URI來表示,如在聯系人應用中,一個指向某聯系人的URI可能為:content://contacts/1。這種URI表示,通過 ContentURI這個類來描述,具體可以參考android.net.ContentURI類的文檔。
此外,除了action和data這兩個重要屬性外,還有一些附加屬性:
category(類別),被執行動作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者應該在Launcher中作為頂級應用出現;而ALTERNATIVE_CATEGORY表示當前的Intent是一系列的可選動作中的一個,這些動作可以在同一塊數據上執行。
type(數據類型),顯式指定Intent的數據類型(MIME)。一般Intent的數據類型能夠根據數據本身進行判定,但是通過設置這個屬性,可以強制采用顯式指定的類型而不再進行推導。
component(組件),指定Intent的的目標組件的類名稱。通常 Android會根據Intent 中包含的其它屬性的信息,比如action、data/type、category進行查找,最終找到一個與之匹配的目標組件。但是,如果 component這個屬性有指定的話,將直接使用它指定的組件,而不再執行上述查找過程。指定了這個屬性以後,Intent的其它所有屬性都是可選的。
extras(附加信息),是其它所有附加信息的集合。使用extras可以為組件提供擴展信息,比如,如果要執行“發送電子郵件”這個動作,可以將電子郵件的標題、正文等保存在extras裡,傳給電子郵件發送組件。
總之,action、 data/type、category和extras 一起形成了一種語言。這種語言使系統能夠理解諸如“查看某聯系人的詳細信息”之類的短語。隨著應用不斷的加入到系統中,它們可以添加新的action、 data/type、category來擴展這種語言。應用也可以提供自己的Activity來處理已經存在的這樣的“短語”,從而改變這些“短語”的行為。
解析Intent
在應用中,我們可以以兩種形式來使用Intent:
· 顯式(直接)Intent:指定了component屬性的Intent(調用setComponent(ComponentName)或者setClass(Context,Class)來指定)。通過指定具體的組件類,通知應用啟動對應的組件。
· 隱式(間接)Intent:沒有指定comonent屬性的Intent。這些Intent需要包含足夠的信息,這樣系統才能根據這些信息,在在所有的可用組件中,確定滿足此Intent的組件。
對於顯式(直接)Intent,Android不需要去做解析,因為目標組件已經很明確,Android需要解析的是那些隱式(間接)Intent,通過解析,將Intent映射給可以處理此Intent的Activity、BroadcastReceiver或Service。
Intent解析機制主要是通過查找已注冊在AndroidManifest.xml中的所有IntentFilter及其中定義的Intent,最終找到匹配的Intent。在這個解析過程中,Android是通過Intent的action、type、category這三個屬性來進行判斷的,判斷方法如下:
· 如果Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,否則不能匹配;
· 如果Intent沒有提供type,系統將從data中得到數據類型。和action一樣,目標組件的數據類型列表中必須包含Intent的數據類型,否則不能匹配。
· 如果Intent中的數據不是content:類型的URI,而且Intent也沒有明確指定它的type,將根據Intent中數據的scheme(比如http:或者mailto:)進行匹配。同上,Intent的scheme必須出現在目標組件的scheme列表中。
· 如果Intent指定了一個或多個category,這些類別必須全部出現在組建的類別列表中。比如Intent中包含了兩個類別:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目標組件必須至少包含這兩個類別。
Intent和IntentFilter
Intent是對需要的聲明。
IntentFilter是在需要時有能力和有興趣提供協助的聲明。
Intent由一系列描述所需動作或服務的信息構成。本節將介紹所請求的動作以及與之相關的數據。
IntentFilter可以是通用的,也可以特定於向某些Intent提供服務。
Intent的動作屬性通常為動詞,例如VIEW、PICK或EDIT。很多內置的Intent動作都是作為Intent類的成員定義的。應用程序開發人員也可以創建新動作。要查看信息,應用程序可以采用以下Intent動作:Intent的數據部分采用URI的形式表示,並且可以是信息的任何部分,例如聯系人記錄、網站位置或對媒體剪輯的引用。
IntentFilter定義Intent與應用程序之間的關系。IntentFilter可以與Intent的數據部分或動作部分相關,或同時與兩者相關。IntentFilter還包含一個category(類別)字段。類別可以幫助對動作進行分類。例如,CATEGORY_LAUNCHER類別指示Android包含此Intent-Filter的Activity在主應用程序啟動器或主界面上應該處於可見狀態。
分發Intent後,系統會計算可用的Activity、Service,以及已注冊的BroadcastReceiver,並將 Intent分發給大多數適當的接收者。
IntentFilter通常在應用程序的AndroidManifest.xml中使用<intent-filter>標記進行定義。從本質上說,AndroidManifest.xml文件就是一個應用程序描述符文件。
下一節介紹,這是 Android 在移動設備屏幕上顯示 UI 元素的機制。
4. Android 視圖——顯示用戶界面(UI)元素
Android 活動通過視圖顯示UI元素。視圖采用以下布局設計之一:
· LinearVertical - 後續的每個元素都排在前一個元素下面,形成一個單一列。
· LinearHorizontal - 後續的每個元素都排在前一個元素右邊,形成一個單一行。
· Relative - 後續的每個元素相對於前一個元素有一定的偏移量。
· Table - 與 HTML 表相似的一系列行和列。每個單元格可以包含一個視圖元素。
選擇一種布局(或布局的組合)之後,就可以用各個視圖顯示 UI。
視圖元素由大家熟悉的 UI 元素組成,包括:
· Button
· ImageButton
· EditText
· TextView(與標簽相似)
· CheckBox
· Radio Button
· Gallery 和 ImageSwitcher(用來顯示多個圖像)
· List
· Grid
· DatePicker
· TimePicker
· Spinner(與組合框相似)
· AutoComplete(具有文本自動補全特性的 EditText)
視圖是在一個 XML 文件中定義的。每個元素都有一個或多個屬於 Android 名稱空間的屬性。
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
眾所周知,一般情況下我們使用android中的monkeyrunner進行自動化測試時,使用的是python語言來寫測試腳本。不過,最近發現可以用java調用mo