Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Application Fundamentals (1/n)

Application Fundamentals (1/n)

編輯:Android開發實例

Android程序是利用Java語言來開發的。編譯完成的java代碼、數據和資源文件是通過一個叫做aapt的工具進行打包,打包之後會生成一個.apk文件。最終用戶可以將.apk文件安裝在Android手機上; 一般情況下,一個.apk文件就被稱為一個應用程序。


每一個Android應用程序都是運行在一個獨立環境中的,這體現在很多方面:
* 默認情況下,每一個Android應用程序都是運行在它自己的linux進程中。當應用程序的任何部分代碼需要被執行時,Android會啟動這個進程來運行它;當不再需要這個應用(即進程)時,並且其它應用請求系統資源時,Android就會關閉這個進程。
* 每一個進程都擁有一個獨立的虛擬機(VM)。所以每一個應用程序相對於其它的應用程序是運行在一個孤島環境中的。
* 默認情況下,每一個Android應用程序都被分配了一個linux用戶id,並且進行了相關的權限設置,所以應用程序的文件只是對本應用程序是可見的(當然,也是一些方式方法來將這些文件導出給其它的應用程序使用)。

多個應用程序是可以分配一個相同的用戶id的,這樣的話,它們就能夠訪問彼此的文件了。多個擁有相同用戶id的應用程序也可以運行在同一個linux進程中,共用一個虛擬機,以節約系統資源。

1. Application Components

Android的一個主要特性就是一個應用程序可以使用其它應用程序的元素(如果其它應用程序許可)。
比如你的應用程序需要顯示一個滾動列表的圖像,並且另外的一個應用程序已經開發出了一個適合的滾動列表,而且允許這個滾動列表被其它的應用程序使用。那麼你就可以調用那個滾動列表來完成工作,而不需要再去開發新的滾動列表。你的應用並不需要包含那個應用程序的代碼,也不需要鏈接它。你只需在你的程序中需要顯示滾動列表的時候,啟動那個應用程序的滾動列表的代碼片段即可。

為了保證上述機制正常工作,當一個應用程序的某部分被請求和需要時,系統必須能夠啟動一個應用程序進程,並且初始化代表那一部分的Java對象。所以,和大多數其它的系統不同,Android應用程序沒有一個唯一的入口(比如說 main 函數),而是擁有一些系統能夠初始化和運行的基本組件。以下是4種基本組件的說明:

1) Activities

一個 activity 代表一個可視化的用戶接口(An activity presents a visual user interface for one focused endeavor the user can undertake)。比如說,一個activity可能代表菜單項的列表,用戶可以從中選擇,或者這個列表顯示一些帶有標題的照片。一個文本短信的應用程序可能有一個顯示通訊錄列表的activity,還有一個給指定聯系人編寫短信的activity,並且可能還有查看以前的短信或是設置的一些activity。雖然它們共同組成了一個緊密結合的用戶界面,但是每一個activity都不依賴其它activity。每一個activity都繼承(extends)android.app.Activity類。

一個應用程序可能只是由一個activity構成,或者由多個activity構成,就像剛剛提到的文本短消息應用程序。具體一個activity是什麼,以及有多少個activity,是由應用程序的設計決定的。典型情況下,有一個activity被標記為主界面(即當系統啟動程序後第一個展現在用戶面前的界面)。從一個activity跳轉到另一個activity是由當前activity發起的。

每一個activity都被賦予一個默認的窗口來進行繪畫。典型情況下,窗口會占滿整個屏幕,但是也可以比屏幕小和漂浮在其它窗口之上。一個activity也可以使用副窗口(additional windows),比如一個要求用戶響應的彈出對話框出現在activity的正中間,或者當用戶選擇了一個條目之後,出現在用戶面前顯示重要信息的窗口。

窗口中可視的內容都是android.view.View類的子類(如TextView)的對象。每一個view控制一個位於窗口中的指定矩形區域。父view包含和組織它的子view的布局。葉子view(即在View繼承樹的最末端)在它自身的控制的矩形區域內進行繪制,並且對用戶在這個矩形區域內的動作做出直接響應。所以,view就是activity與用戶進行交互的場所。比如一個view顯示一張小圖片,並且當用戶點擊這張圖片的時候觸發一個行為(事件)。Android已經內置了一些view,包括按鈕,輸入框,滾動條,菜單項和多選框 等等。

通過調用android.app.Activity.setContentView(View)方法,我們可以給一個activity窗口設置一個完整的View層次樹。其參數是這個View層次樹的最高層的祖先。(想了解更多關於view及其繼承關系的信息,請閱讀 用戶界面 部分)

2) Services
一個Services不擁有可視化的用戶界面,它是在一段不確定的時間周期內在後台運行。比如某個service在後台播放音樂,或者是在後台獲取網絡數據,又或者是進行某個耗時的運算並且將運算結果提供給需要的activity。每一個具體的service是從android.app.Service基類繼承的。

最經典的例子就是一個音樂播放器播放播放列表中的歌曲。這個播放器可能擁有一個或多個activity,比如讓用戶選擇歌曲的activity和播放時的activity等等。然而,真正的播放功能可能並不是由某一個activity來負責的,因為用戶可能期望就算跳轉到任何一個不同的activity都保持歌曲持續不斷地播放。為了達到這個目的,這個播放器的activity需要啟動一個負責播放的service。系統會使這個service在後台持續不斷地運行,哪怕切換到一個新的activity。

我們也可以連接上(綁定)一個正在運行的service(或者是啟動它,前提是這個service還沒有運行)。當連接上之後,你就可以通過這個service導出的接口來與這個service進行通信。針對於播放歌曲的service來說,導出接口可能包括暫停播放、倒退、停止播放和重新播放。

和activity以及其它組件類似,service也是運行在應用程序進程的主線程中的。所以為了不阻塞其它組件的運行和用戶界面的響應,service經常會創建一個新的線程來進行耗時操作(比如像播放音樂)。具體信息請參考"進程和線程"部分。

3) Broadcast receivers
broadcast receiver是一個只能對廣播通告進行接收和響應的組件。有很多的broadcast是由系統發起的,比如說當手機設置的時區發生改變的時候,手機電力不足,某一張圖片被移除,又或者是用戶切換了手機顯示語言。應用程序也可以發起broadcast,比如當一個應用程序成功下載完某些數據後,通知其它的應用程序數據已經准備好。

一個應用程序可以利用任意多的Broadcast receiver來對它感興趣的廣播事件來進行響應。所有的Broadcast receiver都是從 android.content.BroadcastReceiver 類繼承下來的。

broadcast receiver並不會顯示用戶界面。然而,它們可以啟動一個activity來將關於接收的廣播信息提示給用戶,或者它們也可以使用 通知管理器(android.app.NotificationManager) 來提示用戶。一個通知有很多途徑來引起用戶注意,比如點亮手機的背光燈,使手機振動,播放一個提示音等等。經典情況是在狀態欄上顯示一個小圖標,用戶可以點擊這個小圖標以獲取詳細信息。

4) Content providers
Content provider 的作用是將應用程序指定的數據共享給其它的應用程序。這些數據可以是存放在文件系統中的,或是存放在SQLite數據庫文件中,或是以其它任何有意義的方式存放的。一個具體的 Content provider 是繼承於 android.content.ContentProvider 類的,並且實現一系列可以使其它應用程序接收和存儲由此應用程序控制的數據的相關接口即可。然而應用程序並不會直接調用這些接口,它們會利用 android.content.ContentResolver 類的對象來做這個工作,一個 ContentResolver 可以同任何 Content provider 進行通信;它與 Content provider 一起對相關的進程間通信進行管理。

關於如何使用 Content provider 的更多資料,可以參考 Content Providers 章節的內容。

注:任何時候當出現一個應該被某個組件處理的請求,Android都會保證這個組件在應用程序進程中保持運行,必要的話,還會啟動這個組件(必要情況下會創建這個組件對象)使其運行,所以Android也會保證存在這個組件的實例對象。


1.2 Activating components: intents
當 ContentResolver 發出了一個請求,那麼這個請求中所指定的目的 Content providers 會被自動激活。另外三種組件 -- activity, service broadcast receiver -- 是被一種稱為 目的消息(intent) 的異步消息來激活的。一個目的消息是從 android.content.Intent 類繼承的,並且包含了一些內容信息。

對於 activity 和 service 來說,目的消息指定了請求行為和此行為所針對的數據的URI,以及其它信息。比如它可能傳達一個讓某個activity顯示圖片的請求,又或者讓用戶對某些文本信息進行編輯的請求。

對於 broadcast receiver 來說,intent 對象指定了被廣播的行為。比如它可能將拍攝按鈕被按下這個事件(行為)宣布給感興趣的broadcast receiver。


以下是一些激活某一種組件的獨立方法:

1)通過將某個intent對象傳遞給 android.content.Context.startActivity(Intent)android.app.Activity.startActivityForResult(Intent, int) 方法,可以啟動一個activity(或者做一些別的操作)。負責響應的activity(目標activity)可以調用 android.app.Activity.getIntent() 方法來獲取這個Intent對象。若在這之後有新到達的intent,Android系統會調用 android.app.Activity.onNewIntent(Intent) 方法。

通常情況下,一個activity會負責啟動下一個activity,如果想從下一個activity獲取啟動結果碼,可以調用 android.app.Activity.startActivityForResult(Intent, int) 方法。比如說啟動了一個讓用戶挑選圖片的activity,那麼這個activity可能需要將用戶的選擇返回給其它的activity。結果碼是通過 android.app.Activity.onActivityResult(int, int, Intent) 這個方法返回給調用activity的。

2)通過將某個intent對象傳遞給 android.content.Context.startService(Intent) 方法可以啟動一個service(或者給正在運行的service傳遞新的指令)。Android會調用這個service的 android.app.Service(Intent, int) 方法,並傳入這個Intent對象。
與此類似,也可以通過將一個Intent傳遞給 android.content.Context.bindService(Intent, ServiceConnection, int) 方法來與一個正在運行的service建立連接。系統會調用目標service的 android.app.Service.onStart(Intent, int) 方法,並將這個Intent對象傳入(如果service還沒有被啟動的話,bindService 方法可以有選擇地啟動它)。比如一個activity可以和負責播放音樂的service建立連接,這樣的話,這個activity就可以給用戶提供一些用以控制播放行為的接口。這個activity需要首先調用 bindService() 來與service建立連接,然後就可以調用被service定義的方法來控制播放行為了。

關於和 service 綁定的更詳細的信息,在後面的 "遠程過程調用" 章節中被提到。

3)應用程序可以通過將一個 Intent 對象傳遞給android.content.Context.sendBroadcast(Intent)方法,或者android.content.Context.sendOrderedBroadcast(Intent, String)方法,或者android.content.Context.sendStickyBroadcast (Intent)方法以及它們任何的變體形式來產生一個廣播。Android系統會通過調用 android.content.BroadcastReceiver.onReceive (Context, Intent)方法來將這個廣播公告給所有感興趣的 BroadcastReceivers。

關於 目的消息 更多更詳細的資料,請參考 "目的消息和目的消息篩選器" 章節。

1.3 Shutting down components
一個content provider只有在響應一個來自ContentResolver的請求的時候才是激活狀態。類似的,一個broadcast receiver只有在接收適當的廣播消息的時候才是激活狀態。所以沒有必要顯式地關閉這兩種組件。

提供用戶界面的activity則會一直保持激活狀態以便與用戶進行交互。service也是會一直保持激活狀態以便在後台完成指定的任務。所以Android提供了方法來有序地顯式關閉activity和service。

調用android.app.Activity.finish()方法可以關閉自己(activity)。一個activity可以調用android.app.Activity.finishActivity(int)方法來關閉另一個activity(由startActivityForResult()方法激活)。

通過調用android.app.Service.stopSelf()方法可以關閉service,也可以調用android.content.Context.stopService(Intent)方法來關閉。

當組件不再被使用時,或者Android需要激活更多組件從而需要系統資源的時候,組件也可能被系統關閉。在後面的 "組件生命周期" 的章節中會討論這種情況和更詳細的信息。

1.4 The manifest file
要讓Android能啟動一個組件,首先必須要讓Android知道這個組件是存在的。應用程序在manifest文件中聲明它所用到的組件,這個manifest文件也會綁定到 .apk文件中。

所有程序的manifest文件的名字都是 AndroidManifest.xml,並且都是xml格式。除了聲明程序需要用到的組件之外,這個AndroidManifest.xml 也有很多其它功能,比如聲明程序運行時需要用到的非默認鏈接庫,標識程序權限。

AndroidManifest.xml 最重要的功能還是聲明程序需要用到的組件。一個activity可能就是如下的聲明:

<?xml version="1.0" encoding="utf-8"?> 
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
</activity>
. . .
</application>
</manifest>


<activity>
標簽中的name屬性表明從 android.app.Activity類繼承下來的具體的activity類的名字。icon屬性和label屬性表示包含了在這個activity中顯示的圖片和文本的資源文件。

與此類似,<service>標簽代表一個service組件, <receiver>標簽代表一個broadcast receiver組件,而<provider>標簽代表一個content provider組件。

Activities,services,和content provider這3中組件若沒有在 AndroidManifest.xml文件中聲明則不可用。然而,broadcast receiver不但可以聲明在AndroidManifest.xml 文件中,還可以在代碼裡動態創建它們(如android.content.BroadcastReceiver對象),然後調用android.content.Context.registerReceiver(BroadcastReceiver, IntentFilter)方法將其注冊到系統中。

關於manifest文件更詳細的信息,請參考 "AndroidManifest.xml文件" 章節。

1.5 Intent filters (Intents 篩選器)
一個 Intent 對象可以顯式的指定目標組件的名字,這樣的話,Android就會找到這個組件(通過manifest文件中的生命)並且激活它。但是如果沒有顯式的指定目標組件的名字,Android就要負責找到一個最合適的組件來響應這個Intent。Android是通過將這個Intent對象和所有可能的目標組件的intent filter進行比較來篩選出最合適的組件。一個組件的intent filter說明了這個組件可以處理的intent類型。intent filter也是在 manifest 文件中聲明。示例如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
<intent-filter . . . >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter . . . >
<action android:name="com.example.project.BOUNCE" />
<data android:mimeType="image/jpeg" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

</activity>
. . .
</application>
</manifest>

 


示例中的第一個filter是"android.intent.action.MAIN"行為和"android.intent.category.LAUNCHER"類型的組合,這也是一種常用的filter。它表示這個activity是當用戶選擇啟動這個應用程序的時候顯示的第一個界面。

第二個filter聲明表示這個activity可以處理指定類型的數據的行為。

一個組件可以用戶任意多的intent filter,每一個filter聲明了一組不同的能力。若組件沒有沒有聲明任何intent filter,則需要在Intent對象中顯式指明此組件的名字,才能激活這個組件。

對於在代碼中進行創建和注冊的broadcast receiver,一個intent filter直接是由一個android.content.IntentFilter對象來表示的。其余情況,filter都是在manifest文件聲明的。

關於intent filter的更詳細的信息,請參考 "Intent and Intent Filters" 章節。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved