Android Content Provider

内容提供者提供访问数据库的接口,他们封装数据,保护成员变量的私有化。内容提供者是一个标准的接口让一个进程中的数据在另一个进程中运行。
当你想要给内容提供者提供数据时,你可以用一个ContentResolver对象作为客户端使你的应用和内容提供者交流。ContentResolver和provider交流需要有一个类实现ContentProvider的接口。内容提供者从客户端接收数据请求然后将数据放回给客户端,即提供数据源给客户端访问。
如果你不需要把数据提供给其他应用,你就需要自定义内容提供者。如果需要复制粘贴复杂的数据和文件也一样需要自定义。
内容提供者可以让你在多个应用之间共享数据,例如通讯录的数据。如果你不想要数据在多个应用中共享,那么你可以直接使用SQLiteDatabase。
    private static final int PEOPLE = 1;
    private static final int PEOPLE_ID = 2;
    private static final int PEOPLE_PHONES = 3;
    private static final int PEOPLE_PHONES_ID = 4;
    private static final int PEOPLE_CONTACTMETHODS = 7;
    private static final int PEOPLE_CONTACTMETHODS_ID = 8;

    private static final int DELETED_PEOPLE = 20;

    private static final int PHONES = 9;
    private static final int PHONES_ID = 10;
    private static final int PHONES_FILTER = 14;

    private static final int CONTACTMETHODS = 18;
    private static final int CONTACTMETHODS_ID = 19;

    private static final int CALLS = 11;
    private static final int CALLS_ID = 12;
    private static final int CALLS_FILTER = 15;

    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static
    {
        sURIMatcher.addURI("contacts", "people", PEOPLE);
        sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);
        sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);
        sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
        sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);
        sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
        sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);
        sURIMatcher.addURI("contacts", "phones", PHONES);
        sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);
        sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);
        sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);
        sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);
        sURIMatcher.addURI("call_log", "calls", CALLS);
        sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);
        sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
    }

public void addURI (String authority, String path, int code) 这个方法第一个参数authority为内容提供者注册权限时候的authority,第二个参数path一般为要访问的数据源的名字,例如数据库的列表名,第三个参数code为当URI匹配的时候返回给控件的值。

然后在内容提供者中通过UriMatcher匹配解析URI来执行内容提供者为我们提供增删查改的操作。例如:
public class PersonProvider extends ContentProvider
{
    private DBHelper helper;
    private final static UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    private final static int PERSONS = 1;
    private final static int PERSON = 2;
    static
    {
        URI_MATCHER.addURI("com.example.android.PersonProvider", "person", PERSONS);
        URI_MATCHER.addURI("com.example.android.PersonProvider", "person/#", PERSON);
    }
    @Override
    public boolean onCreate()
    {
        helper = new DBHelper(getContext());
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder)
    {
        SQLiteDatabase database = helper.getReadableDatabase();
//      database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
        return null;
    }

    @Override
    public String getType(Uri uri)
    {
        //解析uri
        int flag = URI_MATCHER.match(uri);
        switch (flag)
        {
        case PERSON:
            return "vnd.android.cursor.item/person";
        case PERSONS:
            return "vnd.android.cursor.dir/persons";
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        Uri result = null;
        //解析URI
        int flag = URI_MATCHER.match(uri);
        switch (flag)
        {
        case PERSONS:
            SQLiteDatabase database = helper.getWritableDatabase();
            long id = database.insert("person", null, values);
            result = ContentUris.withAppendedId(uri, id);
            System.out.println("----"+result.toString());
            break;
        }

        return result;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs)
    {
        return 0;
    }

}

接着可以调用相应的函数即可,例如

public void add()
{
    ContentResolver resolver = getContext().getContentResolver();
    ContentValues values = new ContentValues();
    values.put("name", "XX");
    values.put("address", "XXXX");
    //content://authorities/person
    Uri uri = Uri.parse("content://com.example.android.PersonProvider/person");
    resolver.insert(uri, values);
}

一.Content Provider基础

一个内容提供者管理数据存储的借口,它是应用程序的一部分,提供了自己的UI来管理数据,但是,内容提供者主要是供另外的应用使用的,其他应用程序通过一个客户端实例来访问。同时,内容提供者和客户端共享一套恒定的标准的数据接口来交流。
基础包括:
1.内容提供者如何工作?
2.供用户使用的检索数据的API;
3.供用户使用的增删查改的API;
4.其他可以和内容提供者使用的API。

一个内容提供者对内部应用使用一个或多个表格的形式呈现数据,类似数据库中的表格。一行代表了一些内容提供者收集的数据类型的实例,在行里的每列代表了一个属于给类型的数据。例如

![这里写图片描述](https://img-blog.csdn.net/20150926191252880)

注意:内容提供者不需要一个 primary key ,并且它不要求用_ID作为列的名字。但是,如果你想将内容提供者和ListView绑定,其中一列的名字必须为_ID。

1.使用内容提供者

一个应用从内容提供者访问数据是用一个ContentResolver客户端实例,这个实例有和内容提供者同名的方法,ContentResolver提供增删查改的方法。
ContentResolver在客户端应用进程中和ContentProvider在自己的应用中自动地进行内部进程交流,ContentProvider也作为一个抽象的层在数据存储和内部数据表格呈现之间。
注意ContentProvider需要在清单文件中注册。

查找数据可以调用 query(Uri,projection,selection,selectionArgs,sortOrder) 
// 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
第一个参数Uri,它提供了一个表格的检索地址。
projection是一个包含每一行的检索的列的数组。
selection相当于数据库中的where语句。
selectionArgs相当于where语句的占位符。
sortOrder表示排列顺序。    

2.内容提供者的URI

另外Uri包含三个部分:content://com.example.android.PersonProvider/person
content://是内容提供者规定的部分,相当于http://
com.example.android.PersonProvider/是内容提供者的authority,系统就是由这个部分来找到操作哪个ContentProvider,这部分总是固定的。
person是资源部分,这部分在访问不同资源的时候是动态改变的。
Android的Uri功能更加丰富,例如:
content://com.example.android.PersonProvider/person/2                  访问person中ID为2的记录
content://com.example.android.PersonProvider/person/2/person           访问person中ID为2的记录的word字段
content://com.example.android.PersonProvider/persons                   访问全部数据
content://com.example.android.PersonProvider/person/detail/            访问word节点下的detail节点,适用于数据存储于文件,xml,网络中的情况。
parse()方法可以将字符串转换成uri。

3.从内容提供者中得到数据

应遵循的步骤:
1.需要内容提供者的读权限。
2.编写代码发送一个query给内容提供者。
权限在清单文件中添加。

构造query:

第一步就是定义一些内容提供者的用户查询接口,例如:
// 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 = {""};
可以通过SQL的where语句一样筛选数据,如果以上都为空则返回所有数据。

防止恶意输入

显示查询结果

query()返回的是一个Cursor对象。Cursor可以提供行和列的访问。使用Cursor的方法,你可以修改昂的结果,确定每一列的数据类型,得到数据的列和其他性质。一些Cursor的接口还可以在内容提供者改变时自动更新,并且可以在Cursor改变时触发方法。
如果内容提供者没有一行满足条件,则调用Cursor.getCount()是0.
因为Cursor是表格中的一行,所以最适合用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);

从query中得到数据。

例如:


// 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.
}

Curosr的接口包含了很多get方法来得到不同的数据。例如getString() , getType(), getInt()\

4.增删查改

查在上面已经讲过。

调用ContentResolver.insert(),此方法将在ContentProvider中插入一行并且返回该行的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
);
新的一行携带一个ContentValues对象。
_ID这一行是自动保存的,内容提供者提供了一个唯一的_ID给每一行作为主键。URI可以通过_ID来对应数据content://user_dictionary/words/<id_value>,可以通过ContentUris.parseId()得到一个URI的_ID。

调用ContentResolver.update(),同样需要添加一个ContentValues对象。
// 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
);

调用ContentResolver.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
);

5.内容提供者的数据类型

interger,long,float,double
调用Cursor.getType().可以知道数据类型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值