- Android游戲開發(fā)技術(shù)實(shí)戰(zhàn)詳解
- 褚尚軍 張加春編著
- 1341字
- 2018-12-30 05:33:13
2.3 Android系統(tǒng)架構(gòu)剖析
“剖析”二字有“解剖分析”之意,是指對一個(gè)人或一件事做深入的分析,讓別人了解這個(gè)人或明白事情的來龍去脈。學(xué)習(xí)Android之路是一條不平坦的路,需要付出一定的時(shí)間和精力。為了更加深入理解Android的精髓,很有必要了解Android的系統(tǒng)架構(gòu),了解它的組成。這樣才能知道Android究竟能干什么、開發(fā)人員所要學(xué)的是什么。
2.3.1 Android體系結(jié)構(gòu)介紹
Android是一個(gè)移動(dòng)設(shè)備的開發(fā)平臺,其軟件層次結(jié)構(gòu)包括操作系統(tǒng)(OS)、中間件(MiddleWare)和應(yīng)用程序(Application)。根據(jù)Android的軟件框圖,其軟件層次結(jié)構(gòu)自下而上可以分為以下4層。
(1)操作系統(tǒng)層(OS)
(2)各種庫(Libraries)和Android運(yùn)行環(huán)境(RunTime)
(3)應(yīng)用程序框架(Application Framework)
(4)應(yīng)用程序(Application)
上述各層的具體結(jié)構(gòu)如圖2-19所示。

圖2-19 Android操作系統(tǒng)的組件結(jié)構(gòu)圖
1. 操作系統(tǒng)層(OS)——底層
因?yàn)锳ndroid源于Linux,使用了Linux內(nèi)核,所以Android使用Linux 2.6作為操作系統(tǒng)。Linux 2.6是一種標(biāo)準(zhǔn)的技術(shù),Linux也是一個(gè)開放的操作系統(tǒng)。Android對操作系統(tǒng)的使用包括核心和驅(qū)動(dòng)程序兩部分,Android的Linux核心為標(biāo)準(zhǔn)的Linux 2.6內(nèi)核,Android更多的是需要一些與移動(dòng)設(shè)備相關(guān)的驅(qū)動(dòng)程序。主要的驅(qū)動(dòng)如下。
· 顯示驅(qū)動(dòng)(Display Driver):基于Linux的幀緩沖(Frame Buffer)驅(qū)動(dòng);
· Flash內(nèi)存驅(qū)動(dòng)(Flash Memory Driver):基于MTD的Flash驅(qū)動(dòng)程序;
· 相機(jī)驅(qū)動(dòng)(Camera Driver):基于Linux的v4l(Video for Linux)驅(qū)動(dòng);
· 音頻驅(qū)動(dòng)(Audio Driver):基于ALSA(Advanced Linux Sound Architecture,高級Linux聲音體系)驅(qū)動(dòng);
· Wi-Fi驅(qū)動(dòng)(Wi-Fi Driver):基于IEEE 802.11標(biāo)準(zhǔn)的驅(qū)動(dòng)程序;
· 鍵盤驅(qū)動(dòng)(KeyBoard Driver):作為輸入設(shè)備的鍵盤驅(qū)動(dòng);
· 藍(lán)牙驅(qū)動(dòng)(Bluetooth Driver):基于IEEE 802.15.1標(biāo)準(zhǔn)的無線傳輸技術(shù);
· Binder IPC驅(qū)動(dòng):Android中一個(gè)特殊的驅(qū)動(dòng)程序,具有單獨(dú)的設(shè)備節(jié)點(diǎn),提供進(jìn)程間通信的功能;
· Power Management(能源管理):管理電池電量等信息。
2. 各種庫(Libraries)和Android運(yùn)行環(huán)境(RunTime)——中間層
本層次對應(yīng)一般嵌入式系統(tǒng),相當(dāng)于中間件層次。本層次分成兩個(gè)部分,一個(gè)是各種庫,另一個(gè)是Android運(yùn)行環(huán)境。本層的內(nèi)容大多是使用C和C++實(shí)現(xiàn)的。其中包含的各種庫如下所示。
· C庫:C語言的標(biāo)準(zhǔn)庫,也是系統(tǒng)中的底層庫,C庫是通過Linux的系統(tǒng)調(diào)用來實(shí)現(xiàn)的;
·多媒體框架(MediaFramework):這部分內(nèi)容是Android多媒體的核心部分,是基于PacketVideo(即PV)的OpenCORE,從功能上本庫一共分為兩大部分,一部分是音頻、視頻的回放(PlayBack),另一部分則是音、視頻的記錄(Recorder);
· SGL:2D圖像引擎;
· SSL:即Secure Socket Layer,位于TCP/IP協(xié)議與各種應(yīng)用層協(xié)議之間,為數(shù)據(jù)通信提供安全支持;
· OpenGL ES 1.0:提供了對3D的支持;
· 界面管理工具(Surface Management):提供了管理顯示子系統(tǒng)等功能;
· SQLite:一個(gè)通用的嵌入式數(shù)據(jù)庫;
· WebKit:網(wǎng)絡(luò)瀏覽器的核心;
· FreeType:位圖和矢量字體的功能。
Android的各種庫一般是以系統(tǒng)中間件的形式提供的,它們均有的一個(gè)顯著特點(diǎn),就是與移動(dòng)設(shè)備平臺的應(yīng)用密切相關(guān)。
Android運(yùn)行環(huán)境主要是指虛擬機(jī)技術(shù)——Dalvik。Dalvik虛擬機(jī)和一般Java虛擬機(jī)(Java VM)不同,它執(zhí)行的不是Java標(biāo)準(zhǔn)的字節(jié)碼(Bytecode),而是在Dalvik可以執(zhí)行的格式文件(.dex)。在執(zhí)行的過程中,每一個(gè)應(yīng)用程序即一個(gè)進(jìn)程(Linux的一個(gè)Process)。二者最大的區(qū)別在于Java VM是基于棧的虛擬機(jī)(Stack-based),而Dalvik是基于寄存器的虛擬機(jī)(Register-based)。顯然,后者最大的好處在于可以根據(jù)硬件實(shí)現(xiàn)更大的優(yōu)化,這更符合移動(dòng)設(shè)備的特點(diǎn)。
3. 應(yīng)用程序(Application)
Android的應(yīng)用程序主要是用戶界面(User Interface)方面的,通常用Java語言編寫,其中還可以包含各種資源文件(放置在res目錄中)。Java程序及相關(guān)資源經(jīng)過編譯后,將生成一個(gè)APK包。Android本身提供了主屏幕(Home)、聯(lián)系人(Contact)、電話(Phone)、瀏覽器(Browser)等眾多的核心應(yīng)用。同時(shí),應(yīng)用程序的開發(fā)者還可以使用應(yīng)用程序框架層的API實(shí)現(xiàn)自己的程序。這也是Android開源巨大潛力的體現(xiàn)。
4. 應(yīng)用程序框架(Application Framework)
Android的應(yīng)用程序框架為應(yīng)用程序?qū)拥拈_發(fā)者提供API,它實(shí)際上是一個(gè)應(yīng)用程序的框架。由于上層的應(yīng)用程序是以Java構(gòu)建的,因此本層次提供的首先包含了UI程序中所需要的各種控件。例如,Views(視圖組件),其中又包括了List(列表)、Grid(柵格)、Text Box(文本框)、Button(按鈕)等,甚至一個(gè)嵌入式的Web瀏覽器。
一個(gè)基本的Android應(yīng)用程序可以利用應(yīng)用程序框架中的以下五個(gè)部分。
· Activity(活動(dòng))
· Broadcast Intent Receiver(廣播意圖接收者)
· Service(服務(wù))
· Content Provider(內(nèi)容提供者)
· Intent and Intent Filter(意圖和意圖過濾器)
本書的主要目的是講解Android游戲開發(fā)知識,介紹的是應(yīng)用程序(Application)方面的知識。這些知識都是與Java開發(fā)相關(guān)的,當(dāng)然也還需要掌握一些其他層的相關(guān)知識,如底層的內(nèi)核和驅(qū)動(dòng)等知識。
2.3.2 Android應(yīng)用工程文件組成
介紹完Android的整體結(jié)構(gòu)之后,接下來就介紹Android工程文件的組成。因?yàn)锳ndroid游戲項(xiàng)目是用Eclipse創(chuàng)建的工程,所以很有必要了解一個(gè)Android工程文件的結(jié)構(gòu)。
在Eclipse中,一個(gè)基本的Android項(xiàng)目的目錄結(jié)構(gòu)如圖2-20所示。

圖2-20 Android應(yīng)用工程文件組成
1. src目錄——程序文件
在這里保存了程序員直接編寫的程序文件。和一般的Java項(xiàng)目一樣,“src”目錄下保存的是項(xiàng)目的所有包及源文件(.java),“res”目錄下包含了項(xiàng)目中的所有資源,例如,程序圖標(biāo)(drawable)、布局文件(layout)和常量(values)等。不同的是,在Java項(xiàng)目中沒有“gen”目錄,也沒有每個(gè)Android項(xiàng)目都必須有的AndroidManfest.xml文件。
“.java”格式文件是在建立項(xiàng)目時(shí)自動(dòng)生成的,這個(gè)文件是只讀模式,不能更改。R.java文件是定義該項(xiàng)目所有資源的索引文件。先來看看HelloAndroid項(xiàng)目的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; } }
從上述代碼中,可以看到定義了很多常量,并且會(huì)發(fā)現(xiàn)這些常量的名字都與res文件夾中的文件名相同,這再次證明.java文件中存儲的是該項(xiàng)目所有資源的索引。有了這個(gè)文件,在程序中使用資源將變得更加方便,可以很快地找到要使用的資源,由于這個(gè)文件不能被手動(dòng)編輯,所以當(dāng)在項(xiàng)目中加入了新的資源時(shí),只需要刷新一下該項(xiàng)目,.java文件便自動(dòng)生成了所有資源的索引。
2. AndroidManfest.xml文件——設(shè)置文件
文件AndroidManfest.xml是一個(gè)控制文件,在里面包含了該項(xiàng)目中使用的Activity、Service、Receiver,看下面“HelloAndroid”項(xiàng)目中的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啟動(dòng)的位置和時(shí)間。每當(dāng)一個(gè)Activity(或者操作系統(tǒng))要執(zhí)行一個(gè)操作時(shí),它將創(chuàng)建出一個(gè)Intent的對象,這個(gè)Intent對象能承載的信息可描述你想做什么、你想處理什么數(shù)據(jù)與數(shù)據(jù)的類型,以及一些其他信息。而Android能夠?qū)⒚總€(gè)intent-filter數(shù)據(jù)進(jìn)行比較,找到最合適Activity來處理調(diào)用者所指定的數(shù)據(jù)和操作。下面來仔細(xì)分析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>
上述代碼很簡單,就定義了兩個(gè)字符串資源,請不要小看上面的幾行代碼。它們的內(nèi)容很“露臉”,里面的字符直接顯示在手機(jī)屏幕中,就像動(dòng)態(tài)網(wǎng)站中的HTML一樣。
在Android中還有一個(gè)露臉的文件,那就是布局(layout)文件,這個(gè)文件一般位于“res\layout\main.xml”。雖然它里面的字符沒有“露臉”,但是里面的代碼能夠生成一個(gè)顯示界面,這個(gè)可以顯示人名和圖片的界面就“露臉”了。例如:
<?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>
在上述代碼中,有以下幾個(gè)布局和參數(shù)。
· < LinearLayout></LinearLayout>:線性版面配置,在這個(gè)標(biāo)簽中,所有元件都是按自上而下的順序排列而成的。
· android:orientation:表示這個(gè)介質(zhì)的版面配置方式是“從上到下垂直地排列其內(nèi)部的視圖”。
· android:layout_width:定義當(dāng)前視圖在屏幕上所占的寬度,fill_parent即填充整個(gè)屏幕。
· android:layout_height:定義當(dāng)前視圖在屏幕上所占的高度,fill_parent即填充整個(gè)屏幕。
· wrap_content:隨著文字?jǐn)?shù)量的不同而改變這個(gè)視圖的寬度或高度。
在上述布局代碼中,使用了一個(gè)TextView來配置文本標(biāo)簽Widget(構(gòu)件),其中設(shè)置的屬性android:layout_width為整個(gè)屏幕的寬度,android:layout_height可以根據(jù)文字來改變高度,而android:text則設(shè)置了這個(gè)TextView要顯示的文字內(nèi)容,這里引用了@string中的“hello”字符串,即String.xml文件中的“hello”所代表的字符串資源。“hello”字符串的內(nèi)容“Hello World, HelloAndroid!”就是在HelloAndroid項(xiàng)目運(yùn)行時(shí)看到的字符串。
注意:上面介紹的只是主要文件,在項(xiàng)目中需要自行編寫。在項(xiàng)目中還有很多其他的文件,這些文件很少需要編寫,所以在此就不進(jìn)行講解了。
2.3.3 應(yīng)用程序的生命周期
作為一個(gè)程序,也如同自然界的生物一樣,有自己的生命周期。開發(fā)一個(gè)程序的目的是為了完成一項(xiàng)功能,如銀行中計(jì)算加息的軟件。每當(dāng)一個(gè)用戶去柜臺辦理取款業(yè)務(wù)時(shí),銀行工作人員便啟動(dòng)了這個(gè)軟件,當(dāng)用這個(gè)軟件完成利息計(jì)算時(shí),這個(gè)軟件當(dāng)前的任務(wù)就完成了,此時(shí)就需要結(jié)束??隙ㄓ凶x者會(huì)提出疑問:“生生死死”多麻煩,就讓這個(gè)程序一直是“活著”的狀態(tài),一個(gè)用戶辦理完取款業(yè)務(wù)后,繼續(xù)等待下一個(gè)用戶辦理取款業(yè)務(wù),這樣豈不是更方便?但是很不幸,不能這樣做。原因是計(jì)算機(jī)的處理性能是一定的,計(jì)算機(jī)能夠很輕松地完成與一個(gè)人、兩個(gè)人或三個(gè)人相關(guān)的存取款業(yè)務(wù),但是我們開發(fā)的程序軟件需要每天處理成千上萬個(gè)存取款業(yè)務(wù),如果每個(gè)任務(wù)都一直活著,一臺有限配置的計(jì)算機(jī)能承受得了嗎?
由此可見,應(yīng)用程序的生命周期就是一個(gè)程序的存活時(shí)間,即在什么時(shí)間內(nèi)有效。Android是一構(gòu)建在Linux之上的開源移動(dòng)開發(fā)平臺,在Android中,大多數(shù)情況下每個(gè)程序都是在各自獨(dú)立的Linux進(jìn)程中運(yùn)行的。當(dāng)一個(gè)程序或其某些部分被請求時(shí),它的進(jìn)程就“出生”了;當(dāng)這個(gè)程序沒有必要再運(yùn)行下去且系統(tǒng)需要回收這個(gè)進(jìn)程的內(nèi)存用于其他程序時(shí),這個(gè)進(jìn)程就“死亡”了。可以看出,Android程序的生命周期是由系統(tǒng)控制而非程序自身控制的。這和編寫桌面應(yīng)用程序時(shí)的思維有一些不同,一個(gè)桌面應(yīng)用程序的進(jìn)程也是在其他進(jìn)程或用戶請求時(shí)被創(chuàng)建,但是往往是在程序自身收到關(guān)閉請求后執(zhí)行一個(gè)特定的動(dòng)作而結(jié)束進(jìn)程。要想做好某種類型的程序或者某種平臺下的程序的開發(fā),最關(guān)鍵的就是要弄清楚這種類型的程序或整個(gè)平臺下的程序的一般工作模式,并且要做到熟記在心。在Android系統(tǒng)中,程序的生命周期控制就屬于這個(gè)范疇,開發(fā)者必須理解不同的應(yīng)用程序組件,尤其是Activity、Service和Intent Receiver,了解這些組件是如何影響應(yīng)用程序的生命周期的。如果不正確地使用這些組件,可能會(huì)導(dǎo)致系統(tǒng)終止正在執(zhí)行重要任務(wù)的應(yīng)用程序進(jìn)程。
一個(gè)常見的進(jìn)程生命周期漏洞的例子是Intent Receiver(意圖接收器),當(dāng)Intent Receiver在onReceive方法中接收到一個(gè)Intent(意圖)時(shí),它會(huì)啟動(dòng)一個(gè)線程,然后返回。一旦返回,系統(tǒng)將認(rèn)為Intent Receiver不再處于活動(dòng)狀態(tài),因而Intent Receiver所在的進(jìn)程也就不再有用了(除非該進(jìn)程中還有其他的組件處于活動(dòng)狀態(tài))。因此,系統(tǒng)可能會(huì)在任意時(shí)刻終止該進(jìn)程以回收占用的內(nèi)存。這樣進(jìn)程中創(chuàng)建出的那個(gè)線程也將被終止。解決這個(gè)問題的方法是從Intent Receiver中啟動(dòng)一個(gè)服務(wù),讓系統(tǒng)知道進(jìn)程中還有處于活動(dòng)狀態(tài)的工作。為了使系統(tǒng)能夠正確決定在內(nèi)存不足時(shí)應(yīng)該終止哪個(gè)進(jìn)程,Android應(yīng)根據(jù)每個(gè)進(jìn)程中運(yùn)行的組件及組件的狀態(tài)把進(jìn)程放入一個(gè)“Importance Hierarchy(重要性分級)”中。
進(jìn)程的類型多種多樣,按照重要程度主要有如下幾類進(jìn)程。
1. 前臺進(jìn)程(Foreground)
前臺進(jìn)程是看得見的,與用戶當(dāng)前正在做的事情密切相關(guān)的。不同的應(yīng)用程序組件能夠通過不同的方法將它的宿主進(jìn)程移到前臺。在如下的任何一個(gè)條件下“①進(jìn)程正在屏幕的最前端運(yùn)行一個(gè)與用戶交互的活動(dòng)(Activity),它的onResume方法被調(diào)用;②進(jìn)程有一正在運(yùn)行的Intent Receiver(它的IntentReceiver.onReceive方法正在執(zhí)行);③進(jìn)程有一個(gè)服務(wù)(Service),并且在服務(wù)的某個(gè)回調(diào)函數(shù)(Service.onCreate、Service.onStart或Service.onDestroy)內(nèi)有正在執(zhí)行的代碼”,系統(tǒng)將把進(jìn)程移動(dòng)到前臺。
2. 可見進(jìn)程(Visible)
可見進(jìn)程也是可見的,它有一個(gè)可以被用戶從屏幕上看到的活動(dòng),但不在前臺(它的onPause方法被調(diào)用)。例如,前臺的活動(dòng)是一個(gè)對話框,以前的活動(dòng)就隱藏在對話框之后,就會(huì)出現(xiàn)這種進(jìn)程。可見進(jìn)程非常重要,一般不允許被終止,除非是為了保證前臺進(jìn)程的運(yùn)行而不得不終止它。
3. 服務(wù)進(jìn)程(Service)
服務(wù)進(jìn)程是無法看見的,擁有一個(gè)已經(jīng)用startService方法啟動(dòng)的服務(wù)。雖然用戶無法直接看到這些進(jìn)程,但它們做的事情卻是用戶所關(guān)心的(如后臺MP3回放或后臺網(wǎng)絡(luò)數(shù)據(jù)的上傳與下載)。因此,系統(tǒng)將一直運(yùn)行這些進(jìn)程,除非內(nèi)存不足以維持所有的前臺進(jìn)程和可見進(jìn)程。
4. 后臺進(jìn)程(Background)
后臺進(jìn)程也是看不見的,只有打開之后才能看見。例如,迅雷下載,可以將其最小化,雖然桌面上看不見了,但是它一直在進(jìn)行下載的工作。擁有一個(gè)當(dāng)前用戶看不到的活動(dòng)(它的onStop方法被調(diào)用)。這些進(jìn)程對用戶體驗(yàn)沒有直接的影響。如果它們正確執(zhí)行了活動(dòng)生命周期,系統(tǒng)可以在任意時(shí)刻終止該進(jìn)程以回收內(nèi)存,并提供給前面三種類型的進(jìn)程使用。系統(tǒng)中通常有很多這樣的進(jìn)程在運(yùn)行,因此要將這些進(jìn)程保存在LRU列表中,以確保當(dāng)內(nèi)存不足時(shí)用戶最近看到的進(jìn)程最后一個(gè)被終止。
5. 空進(jìn)程(Empty)
不擁有任何活動(dòng)的應(yīng)用程序組件的進(jìn)程。保留這種進(jìn)程的唯一原因是在下次應(yīng)用程序的某個(gè)組件需要運(yùn)行時(shí),不需要重新創(chuàng)建進(jìn)程,這樣可以提高啟動(dòng)速度。
系統(tǒng)將以進(jìn)程中當(dāng)前處于活動(dòng)狀態(tài)組件的重要程度為基礎(chǔ)對進(jìn)程進(jìn)行分類。進(jìn)程的優(yōu)先級可能也會(huì)根據(jù)該進(jìn)程與其他進(jìn)程的依賴關(guān)系而增長。例如,進(jìn)程A通過在進(jìn)程B中設(shè)置Context.BIND_AUTO_CREATE標(biāo)記或使用ContentProvider被綁定到一個(gè)服務(wù)(Service),那么進(jìn)程B在分類時(shí)至少要被看成與進(jìn)程A同等重要。
例如,Activity的狀態(tài)轉(zhuǎn)換圖如圖2-21所示。

圖2-21 Activity狀態(tài)轉(zhuǎn)換圖
圖2-21所示的狀態(tài)的變化是由Android內(nèi)存管理器決定的,Android會(huì)首先關(guān)閉那些包含Inactive Activity的應(yīng)用程序,再關(guān)閉Stopped狀態(tài)的程序。在極端情況下,會(huì)移除Paused狀態(tài)的程序。
- Cisco OSPF命令與配置手冊
- Learning Karaf Cellar
- WordPress 5 Complete
- 物聯(lián)網(wǎng)時(shí)代
- 計(jì)算機(jī)網(wǎng)絡(luò)原理與應(yīng)用技術(shù)
- 中國互聯(lián)網(wǎng)發(fā)展報(bào)告2018
- 物聯(lián)網(wǎng)之霧:基于霧計(jì)算的智能硬件快速反應(yīng)與安全控制
- 物聯(lián)網(wǎng)長距離無線通信技術(shù)應(yīng)用與開發(fā)
- Learning Node.js Development
- AWS Lambda Quick Start Guide
- 云計(jì)算技術(shù)與標(biāo)準(zhǔn)化
- 中國互聯(lián)網(wǎng)發(fā)展報(bào)告2021
- Laravel Application Development Cookbook
- 物聯(lián)網(wǎng)
- 移動(dòng)互聯(lián)網(wǎng)環(huán)境下的核心網(wǎng)剖析及演進(jìn)