概述:做系統或者系統應用開發時經常會需要用到跨進程通信,並且需要傳遞狀態值時,可以通過系統數據庫的屬性進行通信,比如原生系統的設置中的設置休眠時間,usb調試開關等,都是通過Settings.apk中通過選擇項設置一個屬性值,然後再在framework中的相應模塊中通過ContentObserver中的onchange去實現具體的邏輯以達到功能模塊的解耦以及跨進程通信的目的,且系統數據庫中的值類似於contentprovider,是可以在任何其他應用中隨意讀取的(有些屬性值需要權限),寫值的話則需要系統簽名才行,並且可以使用ContentObserver監聽屬性值的變化,不需要像有些場景中需要起個線程去不停的檢測某個值的變化,ContentObserver的onchangge只會在數據變化時纔有回調
1.系統調用流程
1.1最開始是在frameworks\base\packages\SettingsProvider\res\values\defaults.xml中設置默認值,如
<!-- Default for Settings.Secure.USER_SETUP_COMPLETE -->
<bool name="def_user_setup_complete">false</bool>
1.2後面使用到的字符串是在frameworks\base\core\java\android\provider\Settings.java中定義,如
public static final String USER_SETUP_COMPLETE = "user_setup_complete";
1.3僅在第一次開機或者恢復出廠設置時在\frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java中分別通過以下方法加入系統數據庫中
loadSystemSettings(SQLiteDatabase db)--對應數據庫的system表
loadSecureSettings(SQLiteDatabase db)--對應數據庫的secure表
loadGlobalSettings(SQLiteDatabase db)--對應數據庫的global表
說明:以上方法內部會有幾種添加數據類型的方法,如
loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
R.bool.def_guest_user_enabled);//添加boolean類型
loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
R.integer.def_heads_up_enabled);//添加int類型
loadStringSetting(stmt, Settings.Global.DESK_DOCK_SOUND,
R.string.def_desk_dock_sound);//添加string類型
loadSetting(stmt, Settings.Global.SET_INSTALL_LOCATION, 0);
//最終都會走到這個方法中,都是保存的object類型,拿的時候會去判斷類型拿值,再轉換爲相應的類型的值
private void loadSetting(SQLiteStatement stmt, String key, Object value) {
stmt.bindString(1, key);
stmt.bindString(2, value.toString());
stmt.execute();
}
1.4具體數據庫在機器的/data/data/com.android.providers.settings 中,名稱爲settings.db(實際有後綴名,保存時去掉後綴名保存即可,然後可數據庫查看軟件查看裏面的數值)
2.基本使用
2.1添加自定義的字段到數據庫中
\frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java中
loadSystemSettings-loadSetting(stmt,"power_save_mode_state", 0);
說明:上面有提到可以在3個方法下面去加,最後結果就是對應到不同的數據庫表中,如果不閒麻煩可以參考系統的正規流程,在Settings中去去加字符串,然後默認值通過default.xml去定義,然後參考上面1調用流程中的方法去獲得;
2.2讀寫方法
import android.provider.Settings;
Settings.System.getString(mContext.getContentResolver(), "xxx");
Settings.System.putString(mContext.getContentResolver(),"xxx","defaultStr");
Settings.System.getInt(mContext.getContentResolver(),"power_save_mode_state", 0);
Settings.System.putInt(mContext.getContentResolver(),"power_save_mode_state",1);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
說明:注意讀寫方法需要用對應的System/Global/Secure方法,否則讀寫數據會不對應;如果沒在DatabaseHelper.java中添加字段及默認值到數據庫中,也是可以正常用put和get方法的,只是數據庫表中看不到這個字段而已
2.3狀態值改變的監聽
import android.database.ContentObserver;
mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor("power_save_mode_state"), false, mXXXObserver);
private ContentObserver mXXXObserver=new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
};
};
mContext.getContentResolver().unregisterContentObserver(mXXXObserver);
說明:如果是系統源碼裏面去加則注意手動導包