Content Provider基礎(一)

目的

l  原理

l  ContentProvider獲取數據

l  插入、更新、刪除數據

 

 

Content Provider 工作原理

l  概覽

Content Provider對外部應用程序提供數據共享的表示形式,和關係數據庫的表結構類似,例如下面用戶字典的表格。每一行唯一表示了一個單詞的信息。

word

app id

frequency

locale

_ID

mapreduce

user1

100

en_US

1

precompiler

user14

200

fr_FR

2

applet

user2

225

fr_CA

3

const

user1

255

pt_BR

4

int

user5

100

en_UK

5

 

l  訪問Provider

應用程序中需要訪問某個Content Provider的數據是通過ContentResolver對象實現的。Content Provider對象實例的方法提供了基本的CRUD方法用於數據的持久化操作。另外,爲達到這些操作的目的,需要在manifast file中提供相應的權限:Content Provider Permissions.

例如,要查詢Provider所有的用戶單詞和locales,需要調用ContentResolver.query():

 

 

// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    mProjection,                        // The columns to return for each row
    mSelectionClause                    // Selection criteria
    mSelectionArgs,                     // Selection criteria
    mSortOrder);                        // The sort order for the returned rows


 

l  Content URIs

一個content URI 唯一標識了provider的數據資源。每個Content URL包括了Provider的入口和數據表格的路徑(表格的某列)。當我們要去訪問Provider數據資源時,也就是在調用ContentResolver的方法,URI將會作爲一個參數傳入。例如,訪問字典中的單詞時,URI描述如下:

content://user_dictionary/words


 

通常,我們希望獲取某指定行的數據,需要給URI追加指定行的ID,例如,獲取_ID4的行:

 

Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);//withAppendedId用於對URI追加指定的ID。


獲取provider的數據

l  查詢的構建

1.便於後面的處理,下面代碼片段是用於訪問User Dictionary Provider的一些變量定義:

 

// A "projection" defines the columns that will be returned for each row
String[] mProjection =
{
    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
    UserDictionary.Words.WORD,   // Contract class constant for the word column name
    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
};

// Defines a string to contain the selection clause
String mSelectionClause = null;

// Initializes an array to contain selection arguments
String[] mSelectionArgs = {""};


 

2下一個片段中是介紹ContentResolver.query()的詳細使用。對於provider的查詢實際上與SQL有着相同的語法。如下是對word的條件查詢:

 

 

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] mSelectionArgs = {""};

// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
    // Setting the selection clause to null will return all words
    mSelectionClause = null;
    mSelectionArgs[0] = "";

} else {
    // Constructs a selection clause that matches the word that the user entered.
    mSelectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments.
    mSelectionArgs[0] = mSearchString;

}

// Does a query against the table and returns a Cursor object
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    mProjection,                       // The columns to return for each row
    mSelectionClause                   // Either null, or the word the user entered
    mSelectionArgs,                    // Either empty, or the string the user entered
    mSortOrder);                       // The sort order for the returned rows

// Some providers return null if an error occurs, others throw an exception
if (null == mCursor) {
    /*
     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
     * call android.util.Log.e() to log this error.
     *
     */
// If the Cursor is empty, the provider found no matches
} else if (mCursor.getCount() < 1) {

    /*
     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
     * an error. You may want to offer the user the option to insert a new row, or re-type the
     * search term.
     */

} else {
    // Insert code here to do something with the results

}


上面的功能與下面的查詢語句是相似的:

SELECT _ID, word, frequency, locale FROM words WHERE word = <userinput> ORDER BY word ASC;


 

l  防止惡意攻擊和SQL注入

在如下的代碼片段中:

// Constructs a selection clause by concatenating the user's input to the column name
String mSelectionClause =  "var = " + mUserInput;


 

如果用戶輸入nothing; DROP TABLE *,那麼產生的結果是數據庫的表將會全部被清除。

爲了避免這種結果,可以用“?”代替,如:

 

// Constructs a selection clause with a replaceable parameter
String mSelectionClause =  "var = ?";


 

l  數據集的展示

ContentResolver.query()查詢返回一個Cursor實例,它提供按行迭代訪問數據的方法。

如果沒有匹配的查詢結果,返回的Cursor掉用getCount()返回0

如果出現異常,返回null.

我們知道,既然Cursor是一個按行的記錄列(list of rows),比較好的展現數據的形式是通過SimpleCursorAdapter綁定數據的ListView控件。示例片段如下:

 

// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] mWordListColumns =
{
    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
};

// Defines a list of View IDs that will receive the Cursor columns for each row
int[] mWordListItems = { R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter
mCursorAdapter = new SimpleCursorAdapter(
    getApplicationContext(),               // The application's Context object
    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    mCursor,                               // The result from the query
    mWordListColumns,                      // A string array of column names in the cursor
    mWordListItems,                        // An integer array of view IDs in the row layout
    0);                                    // Flags (usually none are needed)

// Sets the adapter for the ListView
mWordList.setAdapter(mCursorAdapter);


 

l  數據集中數據的遍歷

 

// Determine the column index of the column named "word"
int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);

/*
 * Only executes if the cursor is valid. The User Dictionary Provider returns null if
 * an internal error occurs. Other providers may throw an Exception instead of returning null.
 */

if (mCursor != null) {
    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
     * exception.
     */
    while (mCursor.moveToNext()) {

        // Gets the value from the column.
        newWord = mCursor.getString(index);

        // Insert code here to process the retrieved word.

        ...

        // end of while loop
    }
} else {

    // Insert code here to report an error if the cursor is null or the provider threw an exception.
}


 

Cursor提供許多“get”方法來獲取不同類型的數據,如上面的getString().當然,getType()方法可以獲取某一列的數據類型。

插入、更新和刪除數據

l  插入數據

使用ContentResolver.insert()方法來插入一行數據,該方法返回這一行的URI,代碼片段如下:

 

// Defines a new Uri object that receives the result of the insertion
Uri mNewUri;

...

// Defines an object to contain the new values to insert
ContentValues mNewValues = new ContentValues();

/*
 * Sets the values of each column and inserts the word. The arguments to the "put"
 * method are "column name" and "value"
 */
mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
mNewValues.put(UserDictionary.Words.WORD, "insert");
mNewValues.put(UserDictionary.Words.FREQUENCY, "100");

mNewUri = getContentResolver().insert(
    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
    mNewValues                          // the values to insert
);


 

若某一列的數據爲空,則可以賦值null或者使用ContentValues.putNull();我們注意到在插入數據的時候沒有給_ID賦值,這是因爲該列是自增的。在我們不需要_ID的時候完全可以不必要用(ListView 除外);如果需要或得該Uri_ID,調用ContentUris.parseId();

 

l  更新數據

更新數據用到ContentResolver.update();示例如下:

 

// Defines an object to contain the updated values
ContentValues mUpdateValues = new ContentValues();

// Defines selection criteria for the rows you want to update
String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
String[] mSelectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows
int mRowsUpdated = 0;

...

/*
 * Sets the updated value and updates the selected words.
 */
mUpdateValues.putNull(UserDictionary.Words.LOCALE);

mRowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    mUpdateValues                       // the columns to update
    mSelectionClause                    // the column to select on
    mSelectionArgs                      // the value to compare to
);


 

l  刪除數據

 

刪除數據使用getContentResolver().delete.

 

// Defines selection criteria for the rows you want to delete
String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] mSelectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted
int mRowsDeleted = 0;

...

// Deletes the words that match the selection criteria
mRowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    mSelectionClause                    // the column to select on
    mSelectionArgs                      // the value to compare to
);


 

Provider數據類型

Provider提供如下數據類型:

 

text

integer

long integerlong

floating pointfloat

long floating pointdouble

Binary Large ObjectBLOB

 

 

發佈了44 篇原創文章 · 獲贊 115 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章