1. 程式人生 > >探索Settings.System.putInt()

探索Settings.System.putInt()

在android系統移植時,經常要儲存系統某一變數的值,最簡單的方法就是儲存到系統資料庫中,而不是儲存在apk的xml中,只要一句話: 讀也非常簡單: 只要帶一個Context,就可以讀寫這個資料庫,讓我感到困惑的是:對資料庫進行操作,插入和修改是兩種不同命令,android是怎麼知道我到底是進行插入還是修改操作呢?於是跟蹤到原始碼裡看個清楚: 首先,資料庫儲存在哪?      原始碼路徑: \frameworks\base\packages\SettingsProvider\src\com\android\providers\settings                在DatabaseHelper類裡,建立資料庫和表
public class DatabaseHelper extends SQLiteOpenHelper { ......  privatevoid 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);"
);     } privatevoid 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
publicvoid 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  protectedstaticboolean 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); returntrue;             } catch (SQLException e) {                 Log. w( TAG"Can't set key " + name + " in " + uri, e); returnfalse;             }         }