天天看點

探索Settings.System.putInt()

在android系統移植時,經常要儲存系統某一變量的值,最簡單的方法就是儲存到系統資料庫中,而不是儲存在apk的xml中,隻要一句話:

Settings.System.putString(ContentResolver resolver, String name, String value)

讀也非常簡單:

Settings.System.getString(ContentResolver resolver, String name)

隻要帶一個Context,就可以讀寫這個資料庫,讓我感到困惑的是:對資料庫進行操作,插入和修改是兩種不同指令,android是怎麼知道我到底是進行插入還是修改操作呢?于是跟蹤到源碼裡看個清楚:

首先,資料庫儲存在哪?      源碼路徑:           \frameworks\base\packages\SettingsProvider\src\com\android\providers\settings                在 DatabaseHelper類裡,建立資料庫和表 public  class  DatabaseHelper  extends  SQLiteOpenHelper {

......    private   void  createSecureTable(SQLiteDatabase db) {         db.execSQL(  "CREATE TABLE secure ("  +                  "_id INTEGER PRIMARY KEY AUTOINCREMENT,"  +                  "name TEXT UNIQUE ON CONFLICT REPLACE,"  +                  "value TEXT"  +                  ");"  );         db.execSQL(  "CREATE INDEX secureIndex1 ON secure (name);" );     }

     private   void  createGlobalTable(SQLiteDatabase db) {         db.execSQL(  "CREATE TABLE global ("  +                  "_id INTEGER PRIMARY KEY AUTOINCREMENT,"  +                  "name TEXT UNIQUE ON CONFLICT REPLACE,"  +                  "value TEXT"  +                  ");"  );         db.execSQL(  "CREATE INDEX globalIndex1 ON global (name);" );     }      @ Override      public   void  onCreate(SQLiteDatabase db) {         db.execSQL(  "CREATE TABLE system ("  +                      "_id INTEGER PRIMARY KEY AUTOINCREMENT,"  +                      "name TEXT UNIQUE ON CONFLICT REPLACE,"  +                      "value TEXT"  +                      ");"  );         db.execSQL(  "CREATE INDEX systemIndex1 ON system (name);" );

        createSecureTable(db);

         // Only create the global table for the singleton 'owner' user          if  (mUserHandle == UserHandle.USER_OWNER) {             createGlobalTable(db);         }

        db.execSQL(  "CREATE TABLE bluetooth_devices ("  +                      "_id INTEGER PRIMARY KEY,"  +                      "name TEXT,"  +                      "addr TEXT,"  +                      "channel INTEGER,"  +                      "type INTEGER"  +                      ");"  );

        db.execSQL(  "CREATE TABLE bookmarks ("  +                      "_id INTEGER PRIMARY KEY,"  +                      "title TEXT,"  +                      "folder TEXT,"  +                      "intent TEXT,"  +                      "shortcut INTEGER,"  +                      "ordering INTEGER"  +                      ");"  );

        db.execSQL(  "CREATE INDEX bookmarksIndex1 ON bookmarks (folder);" );         db.execSQL(  "CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);" );

         // Populate bookmarks table with initial bookmarks          boolean  onlyCore =  false ;          try  {             onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(                      "package"  )).isOnlyCoreApps();         }  catch  (RemoteException e) {         }          if  (!onlyCore) {             loadBookmarks(db);         }

         // Load initial volume levels into DB         loadVolumeLevels(db);

         // Load inital settings values         loadSettings(db);     }

這裡建立了幾張表,這個資料庫生成的db檔案,儲存成(在android系統):

/data/data/com.android.providers.settings/databases/settings.db

Settings.System.putString()這個方法是把資料寫入到了system表中

至于是插入還是修改,關鍵在于建立表時執行的SQL語句:

  "CREATE TABLE secure ("  +                  "_id INTEGER PRIMARY KEY AUTOINCREMENT,"  +                  "name TEXT UNIQUE ON CONFLICT REPLACE,"  +                  "value TEXT"  +                  ");"

system表中,總共三個字段:_id    name    value

再看下name字段: name TEXT UNIQUE ON CONFLICT REPLACE

ON CONFLICT子句可以定義替代的限制沖突判定算法。預設為ABORT。同一個表中的不同限制可以使用不同的預設沖突判定算法。若一條COPY、INSERT或UPDATE指令指定了不同的沖突判定算法,則該算法将替代CREATE TABLE語句中說明的預設算法

ON CONFLICT子句不是獨立的SQL指令。這是一條可以出現在許多其他SQL指令中的非标準的子句。由于它并不是标準的SQL語言,這裡單獨介紹它。

ON CONFLICT子句的文法在如上的CREATE TABLE指令中示出。對于INSERT和UPDATE,關鍵詞“ON CONFLICT”由“OR”替代,這樣文法顯得自然。例如,不用寫“INSERT ON CONFLICT IGNORE”而是“INSERT OR IGNORE”。二者表示相同的意思。

ON CONFLICT子句定義了解決限制沖突的算法。有五個選擇:ROLLBACK、ABORT、FAIL、IGNORE和REPLACE,預設方案是ABORT。選項含義如下:

ROLLBACK  當發生限制沖突,立即ROLLBACK,即結束目前事務處理,指令中止并傳回SQLITE_CONSTRAINT代碼。若目前無活動事務(除了每一條指令建立的預設事務以外),則該算法與ABORT相同。

ABORT  當發生限制沖突,指令收回已經引起的改變并中止傳回SQLITE_CONSTRAINT。但由于不執行ROLLBACK,是以前面的指令産生的改變将予以保留。預設采用這一行為。

FAIL  當發生限制沖突,指令中止傳回SQLITE_CONSTRAINT。但遇到沖突之前的所有改變将被保留。例如,若一條UPDATE語句在100行遇到沖突100th,前99行的改變将被保留,而對100行或以後的改變将不會發生。

IGNORE  當發生限制沖突,發生沖突的行将不會被插入或改變。但指令将照常執行。在沖突行之前或之後的行将被正常的插入和改變,且不傳回錯誤資訊。

REPLACE  當發生UNIQUE限制沖突,先存在的,導緻沖突的行在更改或插入發生沖突的行之前被删除。這樣,更改和插入總是被執行。指令照常執行且不傳回錯誤資訊。當發生NOT NULL限制沖突,導緻沖突的NULL值會被字段預設值取代。若字段無預設值,執行ABORT算法。

當沖突應對政策為滿足限制而删除行時,它不會調用删除觸發器。但在新版中這一特性可能被改變。

INSERT或UPDATE的OR子句定義的算法會覆寫CREATE TABLE所定義的。ABORT算法将在沒有定義任何算法時預設使用。-->這就是關鍵

以上是資料庫部分 Settings.System源碼路徑:

frameworks\base\core\java\android\provider

 protected   static   boolean  putString(ContentResolver resolver, Uri uri,                 String name, String value) {              // The database will take care of replacing duplicates.              try  {                 ContentValues values =  new  ContentValues();                 values.put(  NAME  , name);                 values.put(  VALUE  , value);                 resolver.insert(uri, values);                  return   true ;             }  catch  (SQLException e) {                 Log. w(  TAG ,  "Can't set key "  + name +  " in "  + uri, e);                  return   false ;             }         }