這個例子源自ActivityManagerService,我們試圖通過它揭示Java層Binder的工作原理。先來描述一下該例子的分析步驟:
- 首先分析AMS如何將自己注冊到ServiceManager。
- 然后分析AMS如何響應客戶端的Binder調用請求。
本例的起點是setSystemProcess,其代碼如下所示:
**ActivityManagerService.java-->ActivityManagerService.setSystemProcess()**
```
public static void setSystemProcess() {
try {
ActivityManagerService m = mSelf;
// 將ActivityManagerService服務注冊到ServiceManager中
ServiceManager.addService("activity", m);......
} catch {... }
return;
}
```
上面所示代碼行的目的是將ActivityManagerService服務(以后簡稱AMS)加到ServiceManager中。
在整個Android系統中有一個Native的ServiceManager(以后簡稱SM)進程,它統籌管理Android系統上的所有Service。成為一個Service的首要條件是先在SM中注冊。下面來看Java層的Service是如何向SM注冊的。
#### 1. 向ServiceManager注冊服務
##### (1)創建ServiceManagerProxy
向SM注冊服務的函數叫addService,其代碼如下:
**ServiceManager.java-->ServiceManager.addService()**
```
public static void addService(String name, IBinderservice) {
try {
//getIServiceManager返回什么
getIServiceManager().addService(name, service);
}
......
}
```
首先需要搞清楚getIServiceManager()方法返回的是一個什么對象呢?參考其實現:
**ServiceManager.java-->ServiceManager.getIServiceManager()**
```
private static IServiceManagergetIServiceManager() {
......
// 調用asInterface,傳遞的參數類型為IBinder
sServiceManager = ServiceManagerNative.asInterface(
BinderInternal.getContextObject());
returnsServiceManager;
}
```
asInterface()方法的參數為BinderInternal.getContextObject()的返回值。于是這個簡短的方法中有兩個內容值得討論:BinderInternal.getContextObject()以及asInterface()。
BinderInternal.getContextObject()方法是一個native的函數,參考其實現:
**android_util_Binder.cpp-->android_os_BinderInternal_getContextObject()**
```
static jobjectandroid_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
/* 下面這句代碼在卷I第6章詳細分析過,它將返回一個BpProxy對象,其中
NULL(即0,用于標識目的端)指定Proxy通信的目的端是ServiceManager*/
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
// 由Native對象創建一個Java對象,下面分析該函數
returnjavaObjectForIBinder(env, b);
}
```
可見,Java層的ServiceManager需要在Native層獲取指向Native進程中ServiceManager的BpProxy。這個BpProxy不能由Java層的ServiceManager直接使用,于是android\_os\_BinderInteral\_getContextObject()函數通過javaObjectForIBinder()函數將創建一個封裝了這個BpProxy的一個Java對象并返回給調用者。ServiceManager便可一通過這個Java對象實現對BpProxy的訪問。參考這個Java對象的創建過程:
**android_util_Binder.cpp-->javaObjectForIBinder()**
```
jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
{
//mProxyLock是一個全局的靜態CMutex對象
AutoMutex _l(mProxyLock);
/* val對象實際類型是BpBinder,讀者可自行分析BpBinder.cpp中的findObject函數。
事實上,在Native層的BpBinder中有一個ObjectManager,它用來管理在Native BpBinder
上創建的Java BpBinder對象。下面這個findObject用來判斷gBinderProxyOffsets
是否已經保存在ObjectManager中。如果是,那就需要刪除這個舊的object */
jobjectobject = (jobject)val->findObject(&gBinderProxyOffsets);
if(object != NULL) {
jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet);
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
// **① 創建一個新的BinderProxy對象。**并將它注冊到Native BpBinder對象的ObjectManager中
object =env->NewObject(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mConstructor);
if(object != NULL) {
/* ② 把Native層的BpProxy的指針保存到BinderProxy對象的成員字段mObject中。
于是BinderProxy對象的Native方法可以通過mObject獲取BpProxy對象的指針。
這個操作是將BinderProxy與BpProxy聯系起來的紐帶 */
env->SetIntField(object, gBinderProxyOffsets.mObject,(int)val.get());
val->incStrong(object);
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
/* 將這個新創建的BinderProxy對象注冊(attach)到BpBinder的ObjectManager中,
同時注冊一個回收函數proxy_cleanup。當BinderProxy對象撤銷(detach)的時候,
該函數會被調用,以釋放一些資源。讀者可自行研究proxy_cleanup函數*/
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
//DeathRecipientList保存了一個用于死亡通知的list
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
//將死亡通知list和BinderProxy對象聯系起來
env->SetIntField(object, gBinderProxyOffsets.mOrgue,
reinterpret_cast<jint>(drl.get()));
// 增加該Proxy對象的引用計數
android_atomic_inc(&gNumProxyRefs);
/*下面這個函數用于垃圾回收。創建的Proxy對象一旦超過200個,該函數
將調用BinderInter類的ForceGc做一次垃圾回收 */
incRefsCreated(env);
}
returnobject;
}
```
BinderInternal.getContextObject的代碼有點多,簡單整理一下,可知該函數完成了以下兩個工作:
- 創建了一個Java層的BinderProxy對象。
- 通過JNI,該BinderProxy對象和一個Native的BpProxy對象掛鉤,而該BpProxy對象的通信目標就是ServiceManager。
接下來討論asInterface()方法,大家還記得在Native層Binder中那個著名的interface\_cast宏嗎?在Java層中,雖然沒有這樣的宏,但是定義了一個類似的函數asInterface。下面來分析ServiceManagerNative類的asInterface函數,其代碼如下:
**ServiceManagerNative.java-->ServiceManagerNative.asInterface()**
```
static public IServiceManager asInterface(IBinderobj)
{
......// 以obj為參數,創建一個ServiceManagerProxy對象
returnnew ServiceManagerProxy(obj);
}
```
上面代碼和Native層interface\_cast非常類似,都是以一個BpProxy對象為參數構造一個和業務相關的Proxy對象,例如這里的ServiceManagerProxy對象。ServiceManagerProxy對象的各個業務函數會將相應請求打包后交給BpProxy對象,最終由BpProxy對象發送給Binder驅動以完成一次通信。
**說明** 實際上BpProxy也不會直接和Binder驅動交互,真正和Binder驅動交互的是IPCThreadState。
##### (2)addService函數分析
現在來分析ServiceManagerProxy的addService函數,其代碼如下:
**ServcieManagerNative.java-->ServiceManagerProxy.addService()**
```
public void addService(String name, IBinderservice)
throwsRemoteException {
Parceldata = Parcel.obtain();
Parcelreply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
// 注意下面這個writeStrongBinder函數,后面我們會詳細分析它
data.writeStrongBinder(service);
/*mRemote實際上就是BinderProxy對象,調用它的transact,將封裝好的請求數據
發送出去 *
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
```
BinderProxy的transact,是一個native函數,其實現函數的代碼如下所示:
**android_util_Binder.cpp-->android_os_BinderProxy_transact()**
```
static jbooleanandroid_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj,
jobject replyObj, jint flags)
{
......
// 從Java的Parcel對象中得到作為參數的Native的Parcel對象
Parcel*data = parcelForJavaObject(env, dataObj);
if (data== NULL) {
return JNI_FALSE;
}
// 得到一個用于接收回復的Parcel對象
Parcel*reply = parcelForJavaObject(env, replyObj);
if(reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
// 從Java的BinderProxy對象中得到之前已經創建好的那個Native的BpBinder對象
IBinder*target = (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
......
// 通過Native的BpBinder對象,將請求發送給ServiceManager
status_terr = target->transact(code, *data, reply, flags);
......
signalExceptionForError(env,obj, err);
returnJNI_FALSE;
}
```
看了上面的代碼會發現,Java層的Binder最終還是要借助Native的Binder進行通信的。
* * * * *
**說明** 從架構的角度看,在Java中搭建了一整套框架,如IBinder接口,Binder類和BinderProxy類。但是從通信角度看,不論架構的編寫采用的是Native語言還是Java語言,只要把請求傳遞到Binder驅動就可以了,所以通信的目的是向binder發送請求和接收回復。在這個目的之上,考慮到軟件的靈活性和可擴展性,于是編寫了一個架構。反過來說,也可以不使用架構(即沒有使用任何接口、派生之類的東西)而直接和binder交互,例如ServiceManager作為Binder的一個核心程序,就是直接讀取/dev/binder設備,獲取并處理請求。從這一點上看,Binder的目的雖是簡單的(即打開binder設備,然后讀請求和寫回復),但是架構是復雜的(編寫各種接口類和封裝類等)。我們在研究源碼時,一定要先搞清楚目的。實現只不過是達到該目的的一種手段和方式。脫離目的的實現,如緣木求魚,很容易偏離事物本質。
* * * * *
在對addService進行分析時曾提示writeStrongBinder是一個特別的函數。那么它特別在哪里呢?下面將給出解釋。
##### (3)三人行之Binder、JavaBBinderHolder和JavaBBinder
ActivityManagerService從ActivityManagerNative類派生,并實現了一些接口,其中和Binder的相關的只有這個ActivityManagerNative類,其原型如下:
**ActivityManagerNative.java-->ActivityManagerNative**
```
public abstract class ActivityManagerNative
extends Binder
implementsIActivityManager
```
ActivityManagerNative從Binder派生,并實現了IActivityManager接口。下面來看ActivityManagerNative的構造函數:
**ActivityManagerNative.java-->ActivityManagerNative.ActivityManagerNative()**
```
public ActivityManagerNative() {
attachInterface(this, descriptor);// 該函數很簡單,讀者可自行分析
}
```
而ActivityManagerNative父類的構造函數則是Binder的構造函數:
**Binder.java-->Binder.Binder()**
```
public Binder() {
init();
}
```
Binder構造函數中會調用native的init函數,其實現的代碼如下:
**android_util_Binder.cpp-->android_os_Binder_init()**
```
static void android_os_Binder_init(JNIEnv* env,jobject obj)
{
// 創建一個JavaBBinderHolder對象
JavaBBinderHolder* jbh = new JavaBBinderHolder();
bh->incStrong((void*)android_os_Binder_init);
// 將這個JavaBBinderHolder對象保存到Java Binder對象的mObject成員中
env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
```
從上面代碼可知,Java的Binder對象將和一個Native的JavaBBinderHolder對象相關聯。那么,JavaBBinderHolder是何方神圣呢?其定義如下:
**android_util_Binder.cpp-->JavaBBinderHolder**
```
class JavaBBinderHolder : public RefBase
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if(b == NULL) {
// 創建一個JavaBBinder,obj實際上是Java層中的Binder對象
b = new JavaBBinder(env, obj);
mBinder = b;
}
return b;
}
......
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
};
```
從派生關系上可以發現,JavaBBinderHolder僅從RefBase派生,所以它不屬于Binder家族。Java層的Binder對象為什么會和Native層的一個與Binder家族無關的對象綁定呢?仔細觀察JavaBBinderHolder的定義可知:JavaBBinderHolder類的get函數中創建了一個JavaBBinder對象,這個對象就是從BnBinder派生的。
那么,這個get函數是在哪里調用的?答案在下面這句代碼中:
```
//其中,data是Parcel對象,service此時還是ActivityManagerService
data.writeStrongBinder(service);
```
writeStrongBinder會做一個替換工作,下面是它的native代碼實現:
**android_util_Binder.cpp-->android_os_Parcel_writeStrongBinder()**
```
static voidandroid_os_Parcel_writeStrongBinder(JNIEnv* env,
jobject clazz, jobject object)
{
/*parcel是一個Native的對象,writeStrongBinder的真正參數是
ibinderForJavaObject()的返回值*/
conststatus_t err = parcel->writeStrongBinder(
ibinderForJavaObject(env, object));
}
[android_util_Binder.cpp-->ibinderForJavaObject()]
sp<IBinder> ibinderForJavaObject(JNIEnv*env, jobject obj)
{
/* 如果Java的obj是Binder類,則首先獲得JavaBBinderHolder對象,然后調用
它的get()函數。而這個get將返回一個JavaBBinder */
if(env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetIntField(obj,
gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
// 如果obj是BinderProxy類,則返回Native的BpBinder對象
if(env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
}
returnNULL;
}
```
根據上面的介紹會發現,addService實際添加到Parcel的并不是AMS本身,而是一個叫JavaBBinder的對象。正是將它最終傳遞到Binder驅動。
讀者此時容易想到,Java層中所有的Binder對應的都是這個JavaBBinder。當然,不同的Binder對象對應不同的JavaBBinder對象。
圖2-2展示了Java Binder、JavaBBinderHolder和JavaBBinder的關系。
:-: 
圖 2 - 2 Java Binder 、JavaBBinderHolder和JavaBBinder三者的關系
從圖2-2可知:
- Java層的Binder通過mObject指向一個Native層的JavaBBInderHolder對象。
- Native層的JavaBBinderHolder對象通過mBinder成員變量指向一個Native的JavaBBinder對象。
- Native的JavaBBinder對象又通過mObject變量指向一個Java層的Binder對象。
為什么不直接讓Java層的Binder對象指向Native層的JavaBBinder對象呢?由于缺乏設計文檔,這里不便妄加揣測,但從JavaBBinderHolder的實現上來分析,估計和垃圾回收(內存管理)有關,因為JavaBBinderHolder中的mBinder對象的類型被定義成弱引用wp了。
>[info] **建議** 對此有更好的解釋的讀者,不妨與大家分享一下。
#### 2. ActivityManagerService響應請求
初見JavaBBinde時,多少有些吃驚。回想一下Native層的Binder架構:雖然在代碼中調用的是Binder類提供的接口,但其對象卻是一個實際的服務端對象,例如MediaPlayerService對象,AudioFlinger對象。
而在Java層的Binder架構中,JavaBBinder卻是一個和業務完全無關的對象。那么,這個對象如何實現不同業務呢?
為回答此問題,我們必須看它的onTransact函數。當收到請求時,系統會調用這個函數。
說明 關于這個問題,建議讀者閱讀卷I第6章“深入理解Binder”。
**android_util_Binder.cpp-->JavaBBinder::onTransact()**
```
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags =0)
{
JNIEnv*env = javavm_to_jnienv(mVM);
IPCThreadState* thread_state = IPCThreadState::self();
.......
// 調用Java層Binder對象的execTranscat函數
jbooleanres = env->CallBooleanMethod(mObject,
gBinderOffsets.mExecTransact,code,
(int32_t)&data, (int32_t)reply, flags);
......
returnres != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
```
就本例而言,上面代碼中的mObject就是ActivityManagerService,現在調用它的execTransact()方法,該方法在Binder類中實現,具體代碼如下:
**Binder.java-->Binder.execTransact()**
```
private boolean execTransact(int code, intdataObj, int replyObj,int flags) {
Parceldata = Parcel.obtain(dataObj);
Parcelreply = Parcel.obtain(replyObj);
booleanres;
try {
//調用onTransact函數,派生類可以重新實現這個函數,以完成業務功能
res= onTransact(code, data, reply, flags);
} catch{ ... }
reply.recycle();
data.recycle();
returnres;
}
```
ActivityManagerNative類實現了onTransact函數,代碼如下:
**ActivityManagerNative.java-->ActivityManagerNative.onTransact()**
```
public boolean onTransact(int code, Parcel data,Parcel reply, int flags)
throws RemoteException {
switch(code) {
caseSTART_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
......
//再由ActivityManagerService實現業務函數startActivity
intresult = startActivity(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, profileFile,
profileFd, autoStopProfiler);
reply.writeNoException();
reply.writeInt(result);
return true;
}
.... // 處理其他請求的case
}
}
```
由此可以看出,JavaBBinder僅是一個傳聲筒,它本身不實現任何業務函數,其工作是:
- 當它收到請求時,只是簡單地調用它所綁定的Java層Binder對象的exeTransact。
- 該Binder對象的exeTransact調用其子類實現的onTransact函數。
- 子類的onTransact函數將業務又派發給其子類來完成。請讀者務必注意其中的多層繼承關系。
通過這種方式,來自客戶端的請求就能傳遞到正確的Java Binder對象了。圖2-3展示AMS響應請求的整個流程。
:-: 
圖 2 - 3 AMS響應請求的流程
在圖2-3中,右上角的大方框表示AMS這個對象,其間的虛線箭頭表示調用子類重載的函數。
- 前言
- 推薦序
- 第1章 開發環境部署
- 1.1獲取Android源代碼
- 1.2Android的編譯
- 1.3在IDE中導入Android源代碼
- 1.3.1將Android源代碼導入Eclipse
- 1.3.2將Android源代碼導入SourceInsight
- 1.4調試Android源代碼
- 1.4.1使用Eclipse調試Android Java源代碼
- 1.4.2使用gdb調試Android C/C 源代碼
- 1.5本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java層中的Binder分析
- 2.2.1Binder架構總覽
- 2.2.2初始化Java層Binder框架
- 2.2.3窺一斑,可見全豹乎
- 2.2.4理解AIDL
- 2.2.5Java層Binder架構總結
- 2.3心系兩界的MessageQueue
- 2.3.1MessageQueue的創建
- 2.3.2提取消息
- 2.3.3nativePollOnce函數分析
- 2.3.4MessageQueue總結
- 2.4本章小結
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量鍵的處理流程
- 3.2.2通用的音量設置函數setStreamVolume()
- 3.2.3靜音控制
- 3.2.4音量控制小結
- 3.3音頻外設的管理
- 3.3.1 WiredAccessoryObserver 設備狀態的監控
- 3.3.2AudioService的外設狀態管理
- 3.3.3音頻外設管理小結
- 3.4AudioFocus機制的實現
- 3.4.1AudioFocus簡單的例子
- 3.4.2AudioFocus實現原理簡介
- 3.4.3申請AudioFocus
- 3.4.4釋放AudioFocus
- 3.4.5AudioFocus小結
- 3.5AudioService的其他功能
- 3.6本章小結
- 第4章 深入理解WindowManager-Service
- 4.1初識WindowManagerService
- 4.1.1一個從命令行啟動的動畫窗口
- 4.1.2WMS的構成
- 4.1.3初識WMS的小結
- 4.2WMS的窗口管理結構
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的顯示次序
- 4.3.1主序、子序和窗口類型
- 4.3.2通過主序與子序確定窗口的次序
- 4.3.3更新顯示次序到Surface
- 4.3.4關于顯示次序的小結
- 4.4窗口的布局
- 4.4.1從relayoutWindow()開始
- 4.4.2布局操作的外圍代碼分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期處理
- 4.4.5布局DisplayContent
- 4.4.6布局的階段
- 4.5WMS的動畫系統
- 4.5.1Android動畫原理簡介
- 4.5.2WMS的動畫系統框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口動畫
- 4.5.5交替運行的布局系統與動畫系統
- 4.5.6動畫系統總結
- 4.6本章小結
- 第5章 深入理解Android輸入系統
- 5.1初識Android輸入系統
- 5.1.1getevent與sendevent工具
- 5.1.2Android輸入系統簡介
- 5.1.3IMS的構成
- 5.2原始事件的讀取與加工
- 5.2.1基礎知識:INotify與Epoll
- 5.2.2 InputReader的總體流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的讀取與加工總結
- 5.3輸入事件的派發
- 5.3.1通用事件派發流程
- 5.3.2按鍵事件的派發
- 5.3.3DispatcherPolicy與InputFilter
- 5.3.4輸入事件的派發總結
- 5.4輸入事件的發送、接收與反饋
- 5.4.1深入理解InputChannel
- 5.4.2連接InputDispatcher和窗口
- 5.4.3事件的發送
- 5.4.4事件的接收
- 5.4.5事件的反饋與發送循環
- 5.4.6輸入事件的發送、接收與反饋總結
- 5.5關于輸入系統的其他重要話題
- 5.5.1輸入事件ANR的產生
- 5.5.2 焦點窗口的確定
- 5.5.3以軟件方式模擬用戶操作
- 5.6本章小結
- 第6章 深入理解控件系統
- 6.1 初識Android的控件系統
- 6.1.1 另一種創建窗口的方法
- 6.1.2 控件系統的組成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的創建與體系結構
- 6.2.2 通過WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 刪除窗口
- 6.2.5 WindowManager的總結
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的創建及其重要的成員
- 6.3.2 控件系統的心跳:performTraversals()
- 6.3.3 ViewRootImpl總結
- 6.4 深入理解控件樹的繪制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()與臟區域
- 6.4.3 開始繪制
- 6.4.4 軟件繪制的原理
- 6.4.5 硬件加速繪制的原理
- 6.4.6 使用繪圖緩存
- 6.4.7 控件動畫
- 6.4.8 繪制控件樹的總結
- 6.5 深入理解輸入事件的派發
- 6.5.1 觸摸模式
- 6.5.2 控件焦點
- 6.5.3 輸入事件派發的綜述
- 6.5.4 按鍵事件的派發
- 6.5.5 觸摸事件的派發
- 6.5.6 輸入事件派發的總結
- 6.6 Activity與控件系統
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的創建與顯示
- 6.7 本章小結
- 第7章 深入理解SystemUI
- 7.1 初識SystemUI
- 7.1.1 SystemUIService的啟動
- 7.1.2 狀態欄與導航欄的創建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的體系結構
- 7.2 深入理解狀態欄
- 7.2.1 狀態欄窗口的創建與控件樹結構
- 7.2.2 通知信息的管理與顯示
- 7.2.3 系統狀態圖標區的管理與顯示
- 7.2.4 狀態欄總結
- 7.3 深入理解導航欄
- 7.3.1 導航欄的創建
- 7.3.2 虛擬按鍵的工作原理
- 7.3.3 SearchPanel
- 7.3.4 關于導航欄的其他話題
- 7.3.5 導航欄總結
- 7.4 禁用狀態欄與導航欄的功能
- 7.4.1 如何禁用狀態欄與導航欄的功能
- 7.4.2 StatusBarManagerService對禁用標記的維護
- 7.4.3 狀態欄與導航欄對禁用標記的響應
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系統中的漫游過程
- 7.5.2 SystemUIVisibility發揮作用
- 7.5.3 SystemUIVisibility總結
- 7.6 本章小結
- 第8章 深入理解Android壁紙
- 8.1 初識Android壁紙
- 8.2深入理解動態壁紙
- 8.2.1啟動動態壁紙的方法
- 8.2.2壁紙服務的啟動原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁紙的銷毀
- 8.2.5 理解Engine的回調
- 8.3 深入理解靜態壁紙-ImageWallpaper
- 8.3.1 獲取用作靜態壁紙的位圖
- 8.3.2 靜態壁紙位圖的設置
- 8.3.3 連接靜態壁紙的設置與獲取-WallpaperObserver
- 8.4 WMS對壁紙窗口的特殊處理
- 8.4.1 壁紙窗口Z序的確定
- 8.4.2 壁紙窗口的可見性
- 8.4.3 壁紙窗口的動畫
- 8.4.4 壁紙窗口總結
- 8.5 本章小結