總結上面所描述的數據更新通知機制的流程如圖8-2所示。
:-: 
圖8-2 數據更新通知的流程圖
從前面的代碼介紹和圖8-2所示的流程來看,Android平臺中的數據更新通知機制還較為簡單。不過此處尚有幾個問題想和讀者一起探討。
問題一:由圖8-2可知,客戶端2調用ContentProvider的update函數將間接觸發客戶端1的ContentObserver的onChange函數被調用。如果客戶端1在onChange函數中耗時過長,會不會導致客戶端2阻塞在update函數中呢?
想到這個問題的讀者應該是非常細致和認真的了。確實,從前面所示的代碼和流程圖來看,這個情況幾乎是必然會發生的,但是實際上該問題并不存在,原因在于下面這一段代碼:
**IContentObserver.java::Proxy:onChange**
~~~
private static class Proxy implementsandroid.database.IContentObserver {
privateandroid.os.IBinder mRemote;
......
publicvoid onChange(boolean selfUpdate)
throws android.os.RemoteException {
android.os.Parcel_data = android.os.Parcel.obtain();
try{
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(((selfUpdate)? (1) : (0)));
//調用客戶端1的ContentObserver Bn端的onChange函數
mRemote.transact(Stub.TRANSACTION_onChange,_data, null,
android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
......
}
~~~
以上代碼告訴我們,ContentService在調用客戶端注冊的IContentObserver 的onChange函數時,使用了FLAG_ONEWAY標志。根據第2章對該標志的介紹(參見2.2.1節),使用該標志的Binder調用只需將請求發給binder驅動即可,無需等待客戶端onChange函數的返回。因此,即使客戶端1在onChange中惡意浪費時間,也不會阻塞客戶端2的update函數了。
問題二:這是一個開放性問題,最終需要讀者給出合適的答案。
假設服務端有一項功能,需要客戶端通過某種方式來控制它的開閉(即禁止或使用該功能),考慮一下有幾種方式來實現這個控制機制。
Android平臺上至少有三種方法可以實現這個控制機制。
- 第一種:服務端實現一個API函數,客戶端直接調用這個函數來控制。
- 第二種客戶端發送指定的廣播,而服務端注冊該廣播的接收者,然后在這個廣播接收者的onReceive函數中去處理。
- 第三種:服務端輸出一個ContentProvider,并為這個功能輸出一個uri地址,然后注冊一個ContentObserver。客戶端可通過更新數據的方式來觸發服務端ContentObserver的onChange函數,服務端在該函數中做對應處理即可。
在Android代碼中,這三種方法都有地方使用。下面將以Settings應用中和USB相關的功能設置為例來觀察第一種和第三種方法的使用情況。
第一個實例和Android 4.0中新支持的USB MTP/PTP功能有關,相關代碼如下:
**UsbSettings.java::onPreferenceTreeClick**
~~~
public booleanonPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
......
if(preference == mMtp) {
mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP,true);
updateToggles(UsbManager.USB_FUNCTION_MTP);
} else if(preference == mPtp) {
mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
updateToggles(UsbManager.USB_FUNCTION_PTP);
}
returntrue;
}
~~~
由以上代碼可知,如果用戶從Settings界面中選擇了使能MTP,將直接調用UsbManager的setCurrentFunction來使能MTP功能。這個函數的Bn端實現在UsbService中。
不過,同樣是USB相關的功能控制,ADB的開關控制卻采用了第三種方法,相關代碼為:
**DevelopmentSettings.java::onClick**
~~~
public void onClick(DialogInterface dialog, intwhich) {
if (which == DialogInterface.BUTTON_POSITIVE){
mOkClicked = true;
//設置Settings數據庫ADB對應的數據項值為1
Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.ADB_ENABLED, 1);
} else
mEnableAdb.setChecked(false);//界面更新
}
~~~
上面的數據項更新操作將導致UsbDeviceManager做對應處理,其相關代碼如下:
**UsbDeviceManager.java::onChange**
~~~
private class AdbSettingsObserver extendsContentObserver {
......
publicvoid onChange(boolean selfChange) {
//從數據庫中取出對應項的值
boolean enable =(Settings.Secure.getInt(mContentResolver,
Settings.Secure.ADB_ENABLED, 0) > 0);
//發送MSG_ENABLE_ADB消息,UsbDeviceManager將處理此消息
mHandler.sendMessage(MSG_ENABLE_ADB, enable);
}
}
~~~
同樣是USB相關的功能,Settings應用卻采用了兩種截然不同的方法來處理它們。這種做法為筆者目前所從事的項目中USB擴展功能的實現帶來了極大困擾,因為我們想采用統一的方法來處理USB相關功能。到底應采用哪種方法比較合適呢?第一種方法和第三種方法各自的適用場景是什么?讀者不妨仔細思考并將結論告訴筆者。
問題三:我們在第7章中分析Cursorquery時曾看到過ContentObserver的身影,但是并沒有對其進行詳細分它。如果現在回過頭去分析query流程中和ContentObserver相關的部分,所涉及的流程可能比本節內容還要多。
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結