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

 

 

你可能感兴趣的:(android,android,Provider,Data,store,content)