AndroidApplication Fundamentals(Android应用基础)
AndroidApplication Fundamentals(Android應用基礎)
?
Android應用采用Java編程語言來編寫,AndroidSDK工具編譯我們的代碼,連同任何數據和資源文件一起打包成一個APK(一個Android package),后綴名為.apk的文件時歸檔文件。一個APK文件包含一個Android 應用的所有內容,且是Android設備用來安裝應用的文件。
?
一旦安裝到設備中,每個Android應用都工作在自己安全的沙箱中(securitysandbox):
(1)????Android操作系統是多用戶的linux系統,每個應用都是一個不同的用戶。
(2)????默認情況下,系統為每個應用分配一個唯一的linux用戶ID(這個ID只能被系統使用,對于應用來說是未知的)。系統為一個應用的所有文件設置權限,所以只有被非配了用戶ID的應用才能夠訪問這些文件。
(3)????每個進程都有自己的虛擬機(VM),所以一個應用的代碼運行在和其他應用相互隔離的空間中。
(4)????默認情況下,每個應用運行在它自己的linux進程中,任何應用的組件(比如activity)需要被執行時Android就會開啟進程,并在不在需要或是系統為其他應用必須回收內存是關閉這個進程。
?
基于上面這些特點,Android系統實現了最小權限原則,也就是說,每個應用默認只能訪問它需要用來實現功能的組件。這樣可以創造一個非常安全的環境,在此環境下,一個應用不能訪問沒有經過授權的系統其他部分。
?
但是,有幾種方式可以讓一個應用共享數據給其他應用,和一個應用可以訪問系統服務:
(1)????為了讓不同應用可以互相訪問彼此的文件,系統可以安排兩個應用共享同一個linux用戶ID。為了節省系統資源,擁有相同用戶ID的應用程序運行在相同的linux進程和共享相同的VM(應用程序也必須使用相同的證書)。
(2)????一個應用能夠請求訪問設備數據的權限,比如用戶的聯系方式(contacts)、短信信息(SMS message)、存儲卡(SD卡)、camera、藍牙、等等,所有應用的權限必須在安裝時由用戶來授權
?
上面的這些描述覆蓋了一個Android應用如何在系統中存在的基礎知識,這個文檔的剩余部分為我們介紹:
(1)????定義了我們應用程序的核心框架組件(core framework components)。
(2)????我們在應用的manifest文件聲明組件(比如activity等)和需要的設備特征(比如拍照)。
(3)????資源獨立于應用代碼,并允許我們的應用程序優雅地優化其行為以適用于多種設備配置。
?
1.??????應用組件(App Components)
應用程序組件式一個Android應用程序的基本構建塊,每個組件是個不同點,系統可以通過它們進入我們的應用程序(Each component is a different point through which the system canenter your app)。不是所有的組件都是用戶的實際入口點,而是一些組件相互依賴,但是每一個作為自己的實體存在和扮演一個特定的角色(每個組件是唯一的構建塊,有助于定義我們APP的整體行為)。
?
Android系統支持4個不同的APP組件,每種類型組件有明顯的目的和定義了組件如何被創建和銷毀的不同的生命周期。
四種APP組件類型如下:
(1)????Activities
Activity我們理解為活動,一個Activity代表用戶界面的一個獨立屏幕,比如,一個郵件APP有一個activity來顯示新郵件列表,另一個activity用于寫一封郵件,并且還有一個activity用于讀郵件。雖然這些activities協同工作以構成郵件APP的緊密結合的用戶體驗,但是每個activity是相互獨立的。因此,一個不同的APP可以啟動這些activities(只要郵件APP允許這樣做)。比如,一個拍照APP為了用戶能夠分享照片,它能夠啟動郵件APP的組件來寫新郵件。
?
???????? 一個activity作為Activity的子類來實現,我們可以通過開發者指南的Activities部分來學習更多關于activity的功能
(http://developer.android.com/reference/android/app/Activity.html)。
?
(2)????Services
Servies理解為服務,services組件運行在后臺以執行長時間的操作或實話執行遠程操作。一個service不提供用戶界面,比如,當用戶在另一個APP時,一個service可在后臺播放音樂,或是從網絡獲取數據而不阻止用戶和一個activity交互。另一種組件,比如activity可以啟動service來讓它運行,或是activity為了和sevice交互而綁定它。一個serice是作為Service的自來的實現。
?
(3)????Content providers
內容提供者,一個content provider管理一組共享的APP數據,我們可以保存這些數據到文件系統、SQLite數據庫、web,或是保存在我們的應用程序能夠訪問的任何其他永久保存的位置。通過content provider,其他APP能夠查詢或甚至是修改這些共享的數據(如果content provider允許這么操作)。比如,Android系統提供一個content provider來管理用戶聯系人信息,因此,有適當權限的任何APP能夠查詢content provider的一部分(比如ContactsContract.Data)來讀和寫一個特定用于的信息。
?
content provider也有助于讀寫我們APP私有數據(不共享),比如記事本示例APP使用一個contentprovider來保存筆記。一個content provider作為ContentProvider的子類來實現,并且必須實現一組標準的API,這樣可使其他APP執行事務。
?
(4)????Broadcast receivers
廣播接收器,一個broadcastreceivers組件響應整個系統的廣播公告,很多廣播產生于系統,比如,一個廣播通知屏幕要已關閉,電池低電量,或是照片被捕獲。APP能夠發起廣播,比如通知其他APP一些數據已經下載完成并且處于可用狀態。雖然broadcast receivers沒有顯示用戶界面,但它們可以在一個廣播事件發生的時候創建一個狀態欄通知來警告用戶。更常見的,雖然一個廣播接收器只是其他組件的“網關”,且適用于用來做最少的工作。比如,它根據事件啟動一個服務來執行一些工作。一個廣播接收器作為BroadcastReceiver的子類來實現,每個廣播以Intent對象的形式被分發出去。
?
Android系統設計一個獨特的一面是任何APP能夠啟動另一個APP的組件,比如,如果我們想要用戶使用帶攝像頭的設備來拍照,可能已經有另一個APP實現了拍照功能,并且我們的APP能夠使用這個拍照功能,而不需要自己來開發一個activity來實現拍照功能,而且我們也不需要包含或是鏈接這個拍照程序。相反,我們能夠簡單的啟動拍照APP的activity來拍照。當拍照完成,照片甚至能夠返回到我們的APP中。對于用戶來說,就像拍照工恩給你是我們APP實際的一部分一樣。
?
???????? 當系統啟動一個組件,如果這個組件所在的程序之前沒有運行,那么系統就開始這個APP的進程,并且實例化(初始化)這個組件所需要的類。比如,如果我們的APP啟動拍照APP的拍照功能對應的activity,這個activity運行在拍照APP的進程,而不是我們APP的進程中。所以,不想其他大部分系統的APP一樣,Android系統的APP沒有一個單獨入口點(比如沒有main函數)。
?
???????? 因為系統每個APP運行在自己獨立的進程中,并且APP中的文件都有自己的權限來限制訪問其他APP。我哦們的AP不能直接激活其他APP的組件,但是Android系統可以,為了激活其他APP的組件,我們必須發送一個說明了我們氣筒一個特定組件的意圖的消息給系統,這樣系統就可以為你激活這個組件。
?
2.??????激活組件(Activating Components)
Android系統4種組件類型中的3種,activity、service和broadcastreceivers這3種是由一種名為intent的異步消息來激活的,這些intents在運行時,把屬于我們的APP或是其他APP的單獨組件綁定在一起,我們可以把intent看做是需要其他組件action(行動)的消息。
?
一個intent是以一個Intent對象的形式創建,intent定義一個激活一個指定組件或是一種指定類型的組件的消息,相應地,intent可以說是顯示或是隱式指定。
?
對于activity和service來說,一個intent定義了要執行的操作(比如要view或是send什么)和指定要操作的數據URI(除此之外,開始的組件也需要知道)。比如,一個intent可能為一個activity發送顯示一張圖片或是打開一個web頁的請求。在某種情況下,我們可以啟動一個activity來獲取返回的結果,在這種情況下,這個activity也能夠返回一個intent結果(比如,我們可以發出一個intent讓用戶選擇一個個人聯系人名(a personal contact)和讓它返回給我們,這個返回的intent包含已選中的contact的URI)。
?
對于廣播接收器,intent簡單的定義了要廣播的通知(announcement)(比如,一個指示設備電池低電量的廣播,只是包含了一個已知動作的字符串(“battery is low”))。
?
另一組件類型內容提供者不是由intent來激活,而是由一個指定請求目標的ContentResolver來激活。這個內容解析器處理所有與內容提供者的直接事務。所以執行提供者事務的內容提供者不需要intent,而是調用ContentResolver對象上的方法來激活。這樣可在內容提供者和這個組件請求的信息保持在一個抽象層(為了安全)。
?
每種類型的組件有自己的辦法來激活相應的組件:
(1)????我們可以通過傳遞一個Intent給startActivity()或startActivityForResult()(如果我們需要這個activity返回結果)啟動一個activity(或是給它一些新的要做的事情)。
(2)????我哦們可以通過傳遞一個Intent給startSevice()來開啟一個service(或是給一個新指令(instructions)給正在運行的serice),或是我們可以傳遞一個Intent給bindService()來綁定一個service。
(3)????我們可以通過傳遞一個intent給sendBroadcast()、sendOrderedBroadcast()或是sendStickyBroadcast()這些方法來發起一個廣播。
(4)????我們可以通關過調用一個ContentResolver對象的query()來查詢一個內容提供者。
?
3.??????Manifest文件
?
在Android系統能夠啟動一個APP組件之前,系統必須通過讀取APP的AndroidManifest.xml(manifest文件)知道APP的組件。我們的APP必須在這個文件中聲明所有的組件,并且這文件必須在APP工程目錄的根目錄下。
?
除了聲明APP的組件之外,manifest文件還做了下面一些事情:
(1)????確定APP需要的任何用戶權限,比如Internet訪問權限或是讀取用戶聯系人權限。
(2)????聲明運行這個APP需要的最低API版本。
(3)????聲明APP需要的硬件和軟件特征,比如攝像頭、藍牙服務或是一個多點觸屏。
(4)????申明該程序需要連接的API庫(不是Android framework的API),比如Google Maps庫。
(5)????等等。
?
4.??????聲明組件(declaring components)
Manifest文件的首要任務是通知系統關于APP中使用的組件,比如一個manifest文件能像下面一樣聲明activity:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
? ? <application android:icon="@drawable/app_icon.png" ... >
? ? ? ? <activity android:name="com.example.project.ExampleActivity"
? ? ? ? ? ? ? ? ? android:label="@string/example_label" ... >
? ? ? ? </activity>
? ? ? ? ...
? ? </application>
</manifest>
在<application>元素中,android:icon屬性指向了標示這個APP的icon資源。
在<activity>元素中,android:name屬性指定了Activity子類的完整類別名稱,android:label屬性指定了標示activity對于用戶可見的label。
?
我們必須用下面的方式來聲明APP的所有組件:
(1)????<activity>元素聲明activities。
(2)????<service>元素聲明services。
(3)????<receiver>元素聲明broadcastreceiver。
(4)????<provider>元素聲明contentprovider。
?
我們在程序中包含了activities、services和content providers,但沒有在mainfest文件中聲明,那么這些組件對系統不可見,因此,這些組件不能運行。但是,broadcast receivers不僅可以再manifest中聲明,也可以在代碼中動態創建(作為BroadcastReceiver對象),并通過調用registerReceiver()在系統中注冊。
?
5.??????聲明組件功能(declaring component capabilities)
正如上面Activating Components部分描述的那樣,我們可以使用一個Intent來啟動activities、services和broadcast receivers,我們可以通過在Intent顯式指定目標組件的名字(使用組件的類名)來實現。但是,intents真正強大的地方在于隱式Intent的概念。一個隱式intent簡單的描述了要執行的組件的操作(并且可以有選擇性地描述要執行操作的數據),允許系統在設備中找到能夠執行這些操作的組件并啟動它。如果有多個組件能夠執行intent描述的操作,用戶可以選擇一個來執行。
?
系統通過比較接收到的intent和定義在設備其他應用manifest文件中的intent filters,從而識別能響應這個intent的組件。
?
當我們在manifest文件中聲明一個activity,我們可選擇地包含intent filters,這些intent filters表明了組件對來之其他APP的intent做出反應的能力。我們可以通過添加一個<intent-filter>元素作為組件聲明元素的子元素來聲明一個intent filter。
?
比如,如果我們已經有一個帶有寫郵件activity的郵件APP,我們像下面一樣聲明一個intent filter來響應“發送”intents(為了發送新郵件):
<manifest ... >
? ? ...
? ? <application ... >
? ? ? ? <activity android:name="com.example.project.ComposeEmailActivity">
? ? ? ? ? ? <intent-filter>
? ? ? ? ? ? ? ? <action android:name="android.intent.action.SEND" />
? ? ? ? ? ? ? ? <data android:type="*/*" />
? ? ? ? ? ? ? ? <category android:name="android.intent.category.DEFAULT" />
? ? ? ? ? ? </intent-filter>
? ? ? ? </activity>
? ? </application>
</manifest>
然后,如果其他APP創建帶有ACTION_SEND操作的intent,并傳遞給startActivity(),系統就能夠啟動找到我們的寫郵件的activity,這樣用戶就能夠編寫和發送郵件。
?
6.??????聲明應用需求(declaring app requirements)
Android支持各種不同的設備 ,并且這些設備提供的特征和功能也不同。為了避免我們的APP安裝在缺少所需要特征的設備上,非常重要的一點是我們通過在manifest文件中聲明設備和軟件需求,來清晰的定義我們APP支持的設備類型。大部分這些聲明只是一些信息和系統并不會讀取它們,但像谷歌市場(Google Play)這樣的外部服務在用戶從他們設備搜索APP是,為用戶提供過濾而讀取這些信息。
?
比如,如果我們的APP需要攝像頭和使用Android 2.1的API版本,我們可以再manifest文件中像下面一樣聲明這些要求:
<manifest ... >
? ? <uses-feature android:name="android.hardware.camera.any"
? ? ? ? ? ? ? ? ? android:required="true" />
? ? <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
? ? ...
</manifest>
由于設備沒有攝像頭和Android版本低于2.1,則不能從谷歌市場中安裝我們的APP。
?
然而,雖然我們不需要攝像頭,但也可以聲明我們的APP使用拍照功能。載那種情況下,我們設置required屬性為false和在運行時檢查設備是否帶有拍照功能,并相應的關閉任何拍照特征。
7.??????應用資源(App Resources)
一個Android APP不僅僅是由代碼組成,它需要和代碼分離的資源,比如圖片、音頻文件和任何與我們APP相關的可視化內容。比如,我們可以定義動畫、菜單、面板、色彩和XML文件中activity用戶界面的布局。使用APP資源資源文件,可以更容易更新我們APP的特性而無需修改代碼。并且通過提供多種可替換的資源文件,使我們可以優化多種配置的設備(比如不用的語言和屏幕大小)。
?
Android工程中每個資源,SDK編譯工具定義一個唯一的整數ID,這樣我們可以在APP代碼或是XML定義的其他資源使用這些ID來引用對應的資源。比如,如果我們的APP包含一個名為logo.png的圖像文件(保存在res/drawable/目錄下),SDK工具產生一個名為R.drawable.logo的資源ID,我們可以可以使用它來引用這張圖片和在用戶界面中插入。
?
資源文件和代碼分開這個機制最主要的一個方面是使我們可以為不同配置的設備提供可替換的資源。比如,在XML中定義UI字符串,我們可以翻譯成其他語言的字符串并保存在獨立的文件中。然后,基于語言標識符,我們添加資源文件夾名稱(比如res/values-fr/對應于法語字符串)和用戶語言設置,這樣Android系統會為我們的UI應用合適的語言字符串。
?
對于我們可替換資源,Android支持多種不同的qualifiers(修飾符),限定符是包含在我們資源文件夾名稱的短字符串,為了便于確定設備配置需要用的資源。再舉另一個例子,對于不同的屏幕分享和大小,我們可能經常為我們的activities創建不同的布局。比如,當設備屏幕是縱向的,我們希望按鍵垂直排列的布局,但如果我們的屏幕是橫向的,按鍵應當是水平排列的。為了根據方向來改變布局,我們可以定義兩個不同的布局,并為每個布局文件夾名稱提供適當的修飾符。這樣,系統可以根據當前設備屏幕的方向來自動應用合適的布局。
?
Android開發者相關鏈接:
http://developer.android.com/guide/components/fundamentals.html
總結
以上是生活随笔為你收集整理的AndroidApplication Fundamentals(Android应用基础)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 当汇错款时该怎么办?
- 下一篇: 并不是所有的程序员都适合做技术管理