ContentProvider自定义-笔记

来源:互联网 发布:在线网页制作软件 编辑:程序博客网 时间:2024/06/11 18:34

对于每一个应用程序来说,要想访问访问内容提供器中共享的数据,就一定要借助 ContentResolve 类,可以通过 Context 中的 getContentResolver() 方法获取到该类的实例,提供了一系列的的方法对数据进行增删改查的操作。

不同于SQLitDatabase,ContentResolver 中增删改查方法都是接受表名参数的,而是使用一个 uri 参数代替,这个参数被称为内容 uri ,它主要由两部分组成,权限(authority)和路径(path)。权限是对不同应用程序做区分,一般用包名,路径是对同一程序中不同的表做区分的,比如某个程序的包名是com.example.app,然后在字符串的头部加上声明协议,一个 uri 就是这个样子的content://com.example.app.provider/table1,可以清楚的表达访问哪个程序中的哪张表。得到了 uri 字符串之后需要将他解析成 uri 对象,只需要调用Uri.parse()方法,就可以将内容URI 字符串解析成Uri 对象了。

Uri uri = Uri.parse("content://com.example.app.provider/table1")

我们就可以使用这个Uri 对象来查询table1 表中的数据

Cursor cursor = getContentResolver().query(        uri,        projection,        selection,        selectionArgs,        sortOrder);

下面是每个参数的意义



接下来简单的写一个获取本地联系人的例子,请看代码.

public class ProviderActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_mvp);        Button btnQuery = (Button) findViewById(R.id.btn_query);        assert btnQuery != null;        btnQuery.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // 查询联系人数据                Cursor cursor = getContentResolver().query(                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,                        null, null, null, null);                assert cursor != null;                while (cursor.moveToNext()) {                    // 获取联系人姓名                    String displayName = cursor.getString(cursor.getColumnIndex(                            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));                    //获取联系人手机号                    String number = cursor.getString(cursor.getColumnIndex(                            ContactsContract.CommonDataKinds.Phone.NUMBER));                    Log.e("ProviderActivity","__displayName" + displayName);                    Log.e("ProviderActivity","__number" + number);                }                cursor.close();            }        });    }}
查询的参数只添加了一个 uri 默认查询所有 ,可以添加别的参数,用法跟数据库查询差不多,剩下的就是一些系统的常量

添加一个权限:

<uses-permission android:name="android.permission.READ_CONTACTS" />
就没什么了。


接下来说说创建自己的内同提供器

首先我们需要创建一个自己的内容提供器 MyProvider 继承自ContentProvider

public class MyProvider extends ContentProvider {    public static final int TABLE1_DIR = 0;  //访问 table1 中所有的数据    public static final int TABLE1_ITEM = 1; //访问 table1 中的单条数据    public static final int TABLE2_DIR = 2;  //访问 table2 中的所有数据     public static final int TABLE2_ITEM = 3; //访问 table2 中的单条数据    private static UriMatcher uriMatcher;    static {        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);        uriMatcher.addURI("com.ning.demosky", "table1", TABLE1_DIR);        uriMatcher.addURI("com.ning.demosky ", "table1/#", TABLE1_ITEM);        uriMatcher.addURI("com.ning.demosky ", "table2", TABLE2_DIR);        uriMatcher.addURI("com.ning.demosky ", "table2/#", TABLE2_ITEM);    }    /**     * 初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,     * 返回true 表示内容提供器初始化成功,返回false 则表示失败。注意,只有当存在     * ContentResolver 尝试访问我们程序中的数据时,内容提供器才会被初始化     */    @Override    public boolean onCreate() {        return false;    }    /**     * 向内容提供器中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据     * 保存在values 参数中。添加完成后,返回一个用于表示这条新记录的URI。     */    @Nullable    @Override    public Uri insert(@NonNull Uri uri, ContentValues values) {        return null;    }    /**     * 从内容提供器中删除数据。使用uri 参数来确定删除哪一张表中的数据,selection     * 和selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。     */    @Override    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {        return 0;    }    /**     * 更新内容提供器中已有的数据。使用uri 参数来确定更新哪一张表中的数据,新数     * 据保存在values 参数中,selection 和selectionArgs 参数用于约束更新哪些行,受影响的     * 行数将作为返回值返回。     */    @Override    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {        return 0;    }    /**     * 从内容提供器中查询数据。使用uri 参数来确定查询哪张表,projection 参数用于确     * 定查询哪些列,selection 和selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于     * 对结果进行排序,查询的结果存放在Cursor 对象中返回     */    @Nullable    @Override    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {      
        //通过上面 uriMatcher.addURI 中自定义的参数来确定所需要执行的操作
switch (uriMatcher.match(uri)) {

case TABLE1_DIR:
// 查询table1表中的所有数据
break;

case
TABLE1_ITEM:
// 查询table1表中的单条数据
break;

case
TABLE2_DIR:
// 查询table2表中的所有数据
break;

case
TABLE2_ITEM:
// 查询table2表中的单条数据
break;

default
:
break;
}

return null; //暂时返回 null
}

/** * 根据传入的内容URI 来返回相应的MIME 类型。 */
@Nullable

@Override

public String getType(@NonNull Uri uri) {

switch (uriMatcher.match(uri)) {

case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider. table1";

case
TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider. table1";

case
TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider. table2";

case
TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider. table2";

default
:
return null;
}
}
}

可以看到几乎每一个方法中都有 uri 参数,这个参数也正是调用 CotentResolver 的增删改查方法传递过来的,而现在,我们需要对传入的 uri 进行解析,从中分析出调用方法期望访问的表和数据。

上面说到,一个标准的内容 uri 写法是这样的,

ontent://com.example.app.provider/table1

这就表示调用方期望访问的  com.example.app.provider 这个应用程序的table1 表中的数据,除此之外,我们还可以在这个内容 uri 后面加上一个 id

ontent://com.example.app.provider/table1/1

这就表示调用方期望访问的是这个应用程序table1id为 1 的数据

我们可以使用分配符的方式来匹配内容 uri

1. *:表示匹配任意长度的任意字符
2. #:表示匹配任意长度的数字
所以,一个能够匹配任意表的内容URI 格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配table1 表中任意一行数据的内容URI 格式就可以写成:
content://com.example.app.provider/table1/#

接下来,我们在借助 UriMatcher 这个类就可以轻松的实现匹配内容 uri 的功能,UriMatcher 提供了一个 addURI 方法,这个方法接收三个参数,可以分别把权限,路径,和一个自定义的代码传进去。这样当调用 UriMatcher 的 match() 方法时,就可以将一个 uri 传入,返回值时某个能够匹配这个 uri 对象所对应的自定义的代码,利用这个代码就可以知道调用方法期望访问哪张表中的数据。


下面说说 getType () 方法,首先要说说 MOME类型 ,网上的解释是 :

 MIME 类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

反正就是一种类型吧,getType()方法。它是所有的内容提供器都必
须提供的一个方法,用于获取Uri 对象所对应的MIME 类型。一个内容URI 所对应的MIME
字符串主要由三部分组分,Android 对这三个部分做了如下格式规定。

1. 必须以vnd 开头。
2. 如果内容URI 以路径结尾,则后接android.cursor.dir/,如果内容URI 以id 结尾,
则后接android.cursor.item/。
3. 最后接上vnd.<authority>.<path>。
所以,对于content://com.example.app.provider/table1 这个内容URI,它所对应的MIME
类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
对于content://com.example.app.provider/table1/1 这个内容URI,它所对应的MIME 类型
就可以写成:
vnd.android.cursor.item/vnd. com.example.app.provider.table1


下面是我写的一个自定义的 ContentProvider 之实现了查询的方法

public class MyProvider extends ContentProvider {    public static final int BOOK_DIR = 0;    public static final int BOOK_ITEM = 1;    public static final int USER_DIR = 2;    public static final int USER_ITEM = 3;    private static UriMatcher uriMatcher;    public static final String AUTHORITY = "com.ning.demosky.provider";    private MyDataBaseHelper dbHelper;    static {        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);        uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);        uriMatcher.addURI(AUTHORITY, "user", USER_DIR);        uriMatcher.addURI(AUTHORITY, "user/#", USER_ITEM);    }    /**     * 初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,     * 返回true 表示内容提供器初始化成功,返回false 则表示失败。注意,只有当存在     * ContentResolver 尝试访问我们程序中的数据时,内容提供器才会被初始化     */    @Override    public boolean onCreate() {        dbHelper = new MyDataBaseHelper(getContext(),"BookStore.db",null,2);        return true;    }    /**     * 向内容提供器中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据     * 保存在values 参数中。添加完成后,返回一个用于表示这条新记录的URI。     */    @Nullable    @Override    public Uri insert(@NonNull Uri uri, ContentValues values) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        switch (uriMatcher.match(uri)){            case BOOK_DIR:                db.insert("book",null,values);                break;        }        return null;    }    /**     * 从内容提供器中删除数据。使用uri 参数来确定删除哪一张表中的数据,selection     * 和selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。     */    @Override    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {        return 0;    }    /**     * 更新内容提供器中已有的数据。使用uri 参数来确定更新哪一张表中的数据,新数     * 据保存在values 参数中,selection 和selectionArgs 参数用于约束更新哪些行,受影响的     * 行数将作为返回值返回。     */    @Override    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {        return 0;    }    /**     * 从内容提供器中查询数据。使用uri 参数来确定查询哪张表,projection 参数用于确     * 定查询哪些列,selection 和selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于     * 对结果进行排序,查询的结果存放在Cursor 对象中返回     */    @Nullable    @Override    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,                        String sortOrder) {        Cursor cursor = null;        SQLiteDatabase db = dbHelper.getWritableDatabase();        switch (uriMatcher.match(uri)) {            case BOOK_DIR:            // 查询book表中的所有数据                cursor = db.query("book",projection,selection,selectionArgs,null,null,sortOrder);                break;            case BOOK_ITEM:            // 查询book表中的单条数据                String bookId = uri.getPathSegments().get(1);                cursor = db.query("book",projection,"id = ?",new String[]{bookId},null,null,sortOrder);                break;            case USER_DIR:            // 查询table2表中的所有数据                cursor = db.query("user",projection,selection,selectionArgs,null,null,sortOrder);                break;            case USER_ITEM:            // 查询table2表中的单条数据                String userId = uri.getPathSegments().get(1);                cursor = db.query("user",projection,"id = ?",new String[]{userId},null,null,sortOrder);                break;            default:                break;        }        return cursor;    }    /**     * 根据传入的内容URI 来返回相应的MIME 类型。     */    @Nullable    @Override    public String getType(@NonNull Uri uri) {        switch (uriMatcher.match(uri)) {            case BOOK_DIR:                return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";            case BOOK_ITEM:                return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";            case USER_DIR:                return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";            case USER_ITEM:                return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";            default:                return null;        }    }}

本应用的 Activity 调用

public class ProviderActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_mvp);        /**         *  "content://com.ning.demosky.provider/book" 完整的叫做内容 uri         *   com.ning.demosky.provider 这个叫做权限,一般是包名 + provider         *   爱叫什么叫什么 ,aaaaa 也可以         * */        final Uri uri = Uri.parse("content://com.ning.demosky.provider/book");        Button btnAdd = (Button) findViewById(R.id.btn_add);        Button btnDelete = (Button) findViewById(R.id.btn_delete);        Button btnUp = (Button) findViewById(R.id.btn_up);        Button btnQuery = (Button) findViewById(R.id.btn_query);        assert btnQuery != null;        btnQuery.setText("查询(长按查本地联系人)");        btnQuery.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                // 查询联系人数据                Cursor cursor = getContentResolver().query(                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,                        null, null, null, null);                assert cursor != null;                while (cursor.moveToNext()) {                    // 获取联系人姓名                    String displayName = cursor.getString(cursor.getColumnIndex(                            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));                    //获取联系人手机号                    String number = cursor.getString(cursor.getColumnIndex(                            ContactsContract.CommonDataKinds.Phone.NUMBER));                    Log.e("ProviderActivity","__displayName" + displayName);                    Log.e("ProviderActivity","__number" + number);                }                cursor.close();                return false;            }        });        btnQuery.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //Cursor cursor = ProviderActivity.this.getContentResolver().query(uri,null,"id = ?",new String[]{"1"},null,null);                Cursor cursor = ProviderActivity.this.getContentResolver().query(uri,null,null,null,null,null);                if (cursor != null){                    while (cursor.moveToNext()){                        String bookName = cursor.getString(cursor.getColumnIndex("name"));                        String bookAuthor = cursor.getString(cursor.getColumnIndex("author"));                        String bookPrice = cursor.getString(cursor.getColumnIndex("price"));                        String bookPages = cursor.getString(cursor.getColumnIndex("pages"));                        Log.e("ProviderActivity","bookName is " + bookName);                        Log.e("ProviderActivity","bookAuthor is " + bookAuthor);                        Log.e("ProviderActivity","bookPrice is " + bookPrice);                        Log.e("ProviderActivity","bookPages is " + bookPages);                    }                    cursor.close();                }            }        });        assert btnAdd != null;        btnAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ContentValues values = new ContentValues();                values.put("name","第二行");                values.put("author","母鸡啊");                values.put("price",10);                values.put("pages",1000);                getContentResolver().insert(uri,values);            }        });        assert btnDelete != null;        btnDelete.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                getContentResolver().delete(uri,"name = ?",new String[]{"第二行"});            }        });        assert btnUp != null;        btnUp.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ContentValues contentValues = new ContentValues();                contentValues.put("name","第三行");                getContentResolver().update(uri,contentValues,"price = ?" ,new String[]{"10"});            }        });    }}


其他应用中的调用 别忘了 在我们的应用  manifest.xml 中进行注册 ,别忘了 在我们的应用  manifest.xml 中进行注册
别忘了 在我们的应用  manifest.xml 中进行注册别忘了 在我们的应用  manifest.xml 中进行注册

<provider    android:name=".view.provider.MyProvider"    android:authorities="com.ning.demosky.provider"    android:exported="true" />

Uri uri = Uri.parse("content://com.ning.demosky.provider/book");Cursor cursor = MainActivity.this.getContentResolver().query(uri,null,null,null,null,null);if (cursor != null){    while (cursor.moveToNext()){        String bookName = cursor.getString(cursor.getColumnIndex("name"));        String bookAuthor = cursor.getString(cursor.getColumnIndex("author"));        String bookPrice = cursor.getString(cursor.getColumnIndex("price"));        String bookPages = cursor.getString(cursor.getColumnIndex("pages"));        Log.e("ProviderActivity","bookName is " + bookName);        Log.e("ProviderActivity","bookAuthor is " + bookAuthor);        Log.e("ProviderActivity","bookPrice is " + bookPrice);        Log.e("ProviderActivity","bookPages is " + bookPages);    }    cursor.close();}


有点乱,有时间在整理吧

如有错误,欢迎指出,不胜感激

0 0
原创粉丝点击