探索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;
            }
        }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章