官术网_书友最值得收藏!

2.3 Android系統架構剖析

“剖析”二字有“解剖分析”之意,是指對一個人或一件事做深入的分析,讓別人了解這個人或明白事情的來龍去脈。學習Android之路是一條不平坦的路,需要付出一定的時間和精力。為了更加深入理解Android的精髓,很有必要了解Android的系統架構,了解它的組成。這樣才能知道Android究竟能干什么、開發人員所要學的是什么。

2.3.1 Android體系結構介紹

Android是一個移動設備的開發平臺,其軟件層次結構包括操作系統(OS)、中間件(MiddleWare)和應用程序(Application)。根據Android的軟件框圖,其軟件層次結構自下而上可以分為以下4層。

(1)操作系統層(OS)

(2)各種庫(Libraries)和Android運行環境(RunTime)

(3)應用程序框架(Application Framework)

(4)應用程序(Application)

上述各層的具體結構如圖2-19所示。

圖2-19 Android操作系統的組件結構圖

1. 操作系統層(OS)——底層

因為Android源于Linux,使用了Linux內核,所以Android使用Linux 2.6作為操作系統。Linux 2.6是一種標準的技術,Linux也是一個開放的操作系統。Android對操作系統的使用包括核心和驅動程序兩部分,Android的Linux核心為標準的Linux 2.6內核,Android更多的是需要一些與移動設備相關的驅動程序。主要的驅動如下。

· 顯示驅動(Display Driver):基于Linux的幀緩沖(Frame Buffer)驅動;

· Flash內存驅動(Flash Memory Driver):基于MTD的Flash驅動程序;

· 相機驅動(Camera Driver):基于Linux的v4l(Video for Linux)驅動;

· 音頻驅動(Audio Driver):基于ALSA(Advanced Linux Sound Architecture,高級Linux聲音體系)驅動;

· Wi-Fi驅動(Wi-Fi Driver):基于IEEE 802.11標準的驅動程序;

· 鍵盤驅動(KeyBoard Driver):作為輸入設備的鍵盤驅動;

· 藍牙驅動(Bluetooth Driver):基于IEEE 802.15.1標準的無線傳輸技術;

· Binder IPC驅動:Android中一個特殊的驅動程序,具有單獨的設備節點,提供進程間通信的功能;

· Power Management(能源管理):管理電池電量等信息。

2. 各種庫(Libraries)和Android運行環境(RunTime)——中間層

本層次對應一般嵌入式系統,相當于中間件層次。本層次分成兩個部分,一個是各種庫,另一個是Android運行環境。本層的內容大多是使用C和C++實現的。其中包含的各種庫如下所示。

· C庫:C語言的標準庫,也是系統中的底層庫,C庫是通過Linux的系統調用來實現的;

·多媒體框架(MediaFramework):這部分內容是Android多媒體的核心部分,是基于PacketVideo(即PV)的OpenCORE,從功能上本庫一共分為兩大部分,一部分是音頻、視頻的回放(PlayBack),另一部分則是音、視頻的記錄(Recorder);

· SGL:2D圖像引擎;

· SSL:即Secure Socket Layer,位于TCP/IP協議與各種應用層協議之間,為數據通信提供安全支持;

· OpenGL ES 1.0:提供了對3D的支持;

· 界面管理工具(Surface Management):提供了管理顯示子系統等功能;

· SQLite:一個通用的嵌入式數據庫;

· WebKit:網絡瀏覽器的核心;

· FreeType:位圖和矢量字體的功能。

Android的各種庫一般是以系統中間件的形式提供的,它們均有的一個顯著特點,就是與移動設備平臺的應用密切相關。

Android運行環境主要是指虛擬機技術——Dalvik。Dalvik虛擬機和一般Java虛擬機(Java VM)不同,它執行的不是Java標準的字節碼(Bytecode),而是在Dalvik可以執行的格式文件(.dex)。在執行的過程中,每一個應用程序即一個進程(Linux的一個Process)。二者最大的區別在于Java VM是基于棧的虛擬機(Stack-based),而Dalvik是基于寄存器的虛擬機(Register-based)。顯然,后者最大的好處在于可以根據硬件實現更大的優化,這更符合移動設備的特點。

3. 應用程序(Application)

Android的應用程序主要是用戶界面(User Interface)方面的,通常用Java語言編寫,其中還可以包含各種資源文件(放置在res目錄中)。Java程序及相關資源經過編譯后,將生成一個APK包。Android本身提供了主屏幕(Home)、聯系人(Contact)、電話(Phone)、瀏覽器(Browser)等眾多的核心應用。同時,應用程序的開發者還可以使用應用程序框架層的API實現自己的程序。這也是Android開源巨大潛力的體現。

4. 應用程序框架(Application Framework)

Android的應用程序框架為應用程序層的開發者提供API,它實際上是一個應用程序的框架。由于上層的應用程序是以Java構建的,因此本層次提供的首先包含了UI程序中所需要的各種控件。例如,Views(視圖組件),其中又包括了List(列表)、Grid(柵格)、Text Box(文本框)、Button(按鈕)等,甚至一個嵌入式的Web瀏覽器。

一個基本的Android應用程序可以利用應用程序框架中的以下五個部分。

· Activity(活動)

· Broadcast Intent Receiver(廣播意圖接收者)

· Service(服務)

· Content Provider(內容提供者)

· Intent and Intent Filter(意圖和意圖過濾器)

本書的主要目的是講解Android游戲開發知識,介紹的是應用程序(Application)方面的知識。這些知識都是與Java開發相關的,當然也還需要掌握一些其他層的相關知識,如底層的內核和驅動等知識。

2.3.2 Android應用工程文件組成

介紹完Android的整體結構之后,接下來就介紹Android工程文件的組成。因為Android游戲項目是用Eclipse創建的工程,所以很有必要了解一個Android工程文件的結構。

在Eclipse中,一個基本的Android項目的目錄結構如圖2-20所示。

圖2-20 Android應用工程文件組成

1. src目錄——程序文件

在這里保存了程序員直接編寫的程序文件。和一般的Java項目一樣,“src”目錄下保存的是項目的所有包及源文件(.java),“res”目錄下包含了項目中的所有資源,例如,程序圖標(drawable)、布局文件(layout)和常量(values)等。不同的是,在Java項目中沒有“gen”目錄,也沒有每個Android項目都必須有的AndroidManfest.xml文件。

“.java”格式文件是在建立項目時自動生成的,這個文件是只讀模式,不能更改。R.java文件是定義該項目所有資源的索引文件。先來看看HelloAndroid項目的R.java文件,如下面的代碼:

package com.yarin.Android.HelloAndroid;
public final class R {
    public static final class attr {
    }
    public static final class drawable {
      public static final int icon=0x7f020000;
    }
    public static final class layout {
      public static final int main=0x7f030000;
    }
    public static final class string {
      public static final int app_name=0x7f040001;
      public static final int hello=0x7f040000;
    }
}

從上述代碼中,可以看到定義了很多常量,并且會發現這些常量的名字都與res文件夾中的文件名相同,這再次證明.java文件中存儲的是該項目所有資源的索引。有了這個文件,在程序中使用資源將變得更加方便,可以很快地找到要使用的資源,由于這個文件不能被手動編輯,所以當在項目中加入了新的資源時,只需要刷新一下該項目,.java文件便自動生成了所有資源的索引。

2. AndroidManfest.xml文件——設置文件

文件AndroidManfest.xml是一個控制文件,在里面包含了該項目中使用的Activity、Service、Receiver,看下面“HelloAndroid”項目中的AndroidManfest.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.yarin.Android.HelloAndroid"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".HelloAndroid"
                android:label="@string/app_name">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="5" />
</manifest>

在上述代碼中,intent-filters描述了Activity啟動的位置和時間。每當一個Activity(或者操作系統)要執行一個操作時,它將創建出一個Intent的對象,這個Intent對象能承載的信息可描述你想做什么、你想處理什么數據與數據的類型,以及一些其他信息。而Android能夠將每個intent-filter數據進行比較,找到最合適Activity來處理調用者所指定的數據和操作。下面來仔細分析AndroidManfest.xml文件,如表2-1所示。

表2-1 AndroidManfest.xml文件分析

3. 常量的定義文件——露臉的文件

下面看看資源文件中一些常量的定義,如String.xml,如下面的代碼:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="hello">Hello World, HelloAndroid!</string>
    <string name="app_name">HelloAndroid</string>
</resources>

上述代碼很簡單,就定義了兩個字符串資源,請不要小看上面的幾行代碼。它們的內容很“露臉”,里面的字符直接顯示在手機屏幕中,就像動態網站中的HTML一樣。

在Android中還有一個露臉的文件,那就是布局(layout)文件,這個文件一般位于“res\layout\main.xml”。雖然它里面的字符沒有“露臉”,但是里面的代碼能夠生成一個顯示界面,這個可以顯示人名和圖片的界面就“露臉”了。例如:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />
</LinearLayout>

在上述代碼中,有以下幾個布局和參數。

· < LinearLayout></LinearLayout>:線性版面配置,在這個標簽中,所有元件都是按自上而下的順序排列而成的。

· android:orientation:表示這個介質的版面配置方式是“從上到下垂直地排列其內部的視圖”。

· android:layout_width:定義當前視圖在屏幕上所占的寬度,fill_parent即填充整個屏幕。

· android:layout_height:定義當前視圖在屏幕上所占的高度,fill_parent即填充整個屏幕。

· wrap_content:隨著文字數量的不同而改變這個視圖的寬度或高度。

在上述布局代碼中,使用了一個TextView來配置文本標簽Widget(構件),其中設置的屬性android:layout_width為整個屏幕的寬度,android:layout_height可以根據文字來改變高度,而android:text則設置了這個TextView要顯示的文字內容,這里引用了@string中的“hello”字符串,即String.xml文件中的“hello”所代表的字符串資源。“hello”字符串的內容“Hello World, HelloAndroid!”就是在HelloAndroid項目運行時看到的字符串。

注意:上面介紹的只是主要文件,在項目中需要自行編寫。在項目中還有很多其他的文件,這些文件很少需要編寫,所以在此就不進行講解了。

2.3.3 應用程序的生命周期

作為一個程序,也如同自然界的生物一樣,有自己的生命周期。開發一個程序的目的是為了完成一項功能,如銀行中計算加息的軟件。每當一個用戶去柜臺辦理取款業務時,銀行工作人員便啟動了這個軟件,當用這個軟件完成利息計算時,這個軟件當前的任務就完成了,此時就需要結束。肯定有讀者會提出疑問:“生生死死”多麻煩,就讓這個程序一直是“活著”的狀態,一個用戶辦理完取款業務后,繼續等待下一個用戶辦理取款業務,這樣豈不是更方便?但是很不幸,不能這樣做。原因是計算機的處理性能是一定的,計算機能夠很輕松地完成與一個人、兩個人或三個人相關的存取款業務,但是我們開發的程序軟件需要每天處理成千上萬個存取款業務,如果每個任務都一直活著,一臺有限配置的計算機能承受得了嗎?

由此可見,應用程序的生命周期就是一個程序的存活時間,即在什么時間內有效。Android是一構建在Linux之上的開源移動開發平臺,在Android中,大多數情況下每個程序都是在各自獨立的Linux進程中運行的。當一個程序或其某些部分被請求時,它的進程就“出生”了;當這個程序沒有必要再運行下去且系統需要回收這個進程的內存用于其他程序時,這個進程就“死亡”了。可以看出,Android程序的生命周期是由系統控制而非程序自身控制的。這和編寫桌面應用程序時的思維有一些不同,一個桌面應用程序的進程也是在其他進程或用戶請求時被創建,但是往往是在程序自身收到關閉請求后執行一個特定的動作而結束進程。要想做好某種類型的程序或者某種平臺下的程序的開發,最關鍵的就是要弄清楚這種類型的程序或整個平臺下的程序的一般工作模式,并且要做到熟記在心。在Android系統中,程序的生命周期控制就屬于這個范疇,開發者必須理解不同的應用程序組件,尤其是Activity、Service和Intent Receiver,了解這些組件是如何影響應用程序的生命周期的。如果不正確地使用這些組件,可能會導致系統終止正在執行重要任務的應用程序進程。

一個常見的進程生命周期漏洞的例子是Intent Receiver(意圖接收器),當Intent Receiver在onReceive方法中接收到一個Intent(意圖)時,它會啟動一個線程,然后返回。一旦返回,系統將認為Intent Receiver不再處于活動狀態,因而Intent Receiver所在的進程也就不再有用了(除非該進程中還有其他的組件處于活動狀態)。因此,系統可能會在任意時刻終止該進程以回收占用的內存。這樣進程中創建出的那個線程也將被終止。解決這個問題的方法是從Intent Receiver中啟動一個服務,讓系統知道進程中還有處于活動狀態的工作。為了使系統能夠正確決定在內存不足時應該終止哪個進程,Android應根據每個進程中運行的組件及組件的狀態把進程放入一個“Importance Hierarchy(重要性分級)”中。

進程的類型多種多樣,按照重要程度主要有如下幾類進程。

1. 前臺進程(Foreground)

前臺進程是看得見的,與用戶當前正在做的事情密切相關的。不同的應用程序組件能夠通過不同的方法將它的宿主進程移到前臺。在如下的任何一個條件下“①進程正在屏幕的最前端運行一個與用戶交互的活動(Activity),它的onResume方法被調用;②進程有一正在運行的Intent Receiver(它的IntentReceiver.onReceive方法正在執行);③進程有一個服務(Service),并且在服務的某個回調函數(Service.onCreate、Service.onStart或Service.onDestroy)內有正在執行的代碼”,系統將把進程移動到前臺。

2. 可見進程(Visible)

可見進程也是可見的,它有一個可以被用戶從屏幕上看到的活動,但不在前臺(它的onPause方法被調用)。例如,前臺的活動是一個對話框,以前的活動就隱藏在對話框之后,就會出現這種進程。可見進程非常重要,一般不允許被終止,除非是為了保證前臺進程的運行而不得不終止它。

3. 服務進程(Service)

服務進程是無法看見的,擁有一個已經用startService方法啟動的服務。雖然用戶無法直接看到這些進程,但它們做的事情卻是用戶所關心的(如后臺MP3回放或后臺網絡數據的上傳與下載)。因此,系統將一直運行這些進程,除非內存不足以維持所有的前臺進程和可見進程。

4. 后臺進程(Background)

后臺進程也是看不見的,只有打開之后才能看見。例如,迅雷下載,可以將其最小化,雖然桌面上看不見了,但是它一直在進行下載的工作。擁有一個當前用戶看不到的活動(它的onStop方法被調用)。這些進程對用戶體驗沒有直接的影響。如果它們正確執行了活動生命周期,系統可以在任意時刻終止該進程以回收內存,并提供給前面三種類型的進程使用。系統中通常有很多這樣的進程在運行,因此要將這些進程保存在LRU列表中,以確保當內存不足時用戶最近看到的進程最后一個被終止。

5. 空進程(Empty)

不擁有任何活動的應用程序組件的進程。保留這種進程的唯一原因是在下次應用程序的某個組件需要運行時,不需要重新創建進程,這樣可以提高啟動速度。

系統將以進程中當前處于活動狀態組件的重要程度為基礎對進程進行分類。進程的優先級可能也會根據該進程與其他進程的依賴關系而增長。例如,進程A通過在進程B中設置Context.BIND_AUTO_CREATE標記或使用ContentProvider被綁定到一個服務(Service),那么進程B在分類時至少要被看成與進程A同等重要。

例如,Activity的狀態轉換圖如圖2-21所示。

圖2-21 Activity狀態轉換圖

圖2-21所示的狀態的變化是由Android內存管理器決定的,Android會首先關閉那些包含Inactive Activity的應用程序,再關閉Stopped狀態的程序。在極端情況下,會移除Paused狀態的程序。

主站蜘蛛池模板: 壶关县| 天峻县| 星座| 嫩江县| 鄂托克旗| 涿鹿县| 时尚| 吉木萨尔县| 洛阳市| 龙游县| 南丹县| 浙江省| 富源县| 东至县| 锦州市| 岑巩县| 通榆县| 广安市| 新民市| 蕉岭县| 阿克陶县| 永兴县| 新宾| 宿松县| 双桥区| 胶南市| 大理市| 永州市| 金溪县| 平武县| 绿春县| 静宁县| 安国市| 定结县| 祁阳县| 铜陵市| 资溪县| 静安区| 和田县| 工布江达县| 大石桥市|