Content Provider使用良心总结

1.简介
Content Provider主要用于在不同的应用程序之间(因而是完成IPC的一种)实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用ContentProviderAndroid 实现跨程序共享数据的标准方式,因为它提供了统一的数据访问方式。

2.使用
一种是使用现有的ContentProvider来读取和操作相应程序中的数据eg:读取电话簿,通讯录信息);

· 另一种是创建自己的Contentprovider为其它应用程序提供数据访问的外部接口。

· 对于每一个应用程序来说,如果想要访问内容提供器中共享的数据,就一定要借助ContentResolve类,可以通过 Context中的 getContentResolver()方法获取到该类的实例。

· ContentResolver 中提供了一系列的方法用于对数据进行 CRUD 操作。类似于SQLite中数据操作。

 

3.自定义contentprovider
很简单,通过继承contentprovider抽象类,并实现6个必要的方法;
onCreate() //contentprovider创建时候调用,完成初始化工作,由系统回调并运行在UI线程中。
String getTypeURI uri//用于返回一个URI所对应的MIME类型;(这里不太明白)
除了上边几个方法,还有四个方法是用于CRUD的,他们完成与数据库之间的交互,运行在Binder线程池中(包括getType方法)。

4. contentprovider又是如何确定究竟是访问的那些数据?

数据是以集合的形式存在于数据库中,contentprovider提供了Uri来区分外界要访问的具体数据集合

egcontent://com.exam.demodata.utils.MyContentProvider/person/2
上面的URI可以由3部分组成:
scheme规定为content://,默认
Authority用于标识一个contentprovider,便于外部访问者能找到它。也就是在注册文件中authorities中的内容;
path用于标识要操作的数据的具体路径;上面的URI中的path部分为/person/2 表示应用程序将访问person表中id2的数据。
又如,操作的是整个表,path/person

5.UriMatcher类:
为了知道外界将要访问的数据集合,通常会在contentprovider中自定义URIURI_CODE,将它们一一关联。而这步操作通常是由UriMatcher类完成。
通过UriMatcheraddURI()方法建立URIURI_CODE之间的关联,我们就可以根据URI得到URI_CODEmatch方法),从而找到将要操作的具体数据。
eg:当contentprovider要提供对两个表的操作,可以通过此方法来确定外界究竟要访问那个表。

private MyDbHelper dbHelper;

    private static final String authority="com.exam.demodata.utils.MyContentProvider";

    public static final Uri contentUri

    =Uri.parse("content://"+authority+"/person");

 

    private static UriMatcher uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);

    static{

        Log.i("info", "static");

        uriMatcher.addURI(authority, "person", 1);

        uriMatcher.addURI(authority, "person/#", 2);

    }

 

    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

        // TODO Auto-generated method stub

        SQLiteDatabase database=dbHelper.getWritableDatabase();

        int num=0;

        switch (uriMatcher.match(uri)) {

        case 1:

            num = database.delete("person", selection, selectionArgs);

            break;

        case 2:

            long id=ContentUris.parseId(uri);

            if(selection==null){

                selection="id="+id;

            }else{

                selection="id=+"+id+"and ("+selection+")";

            }

            num=database.delete("person", selection, selectionArgs);

            break;

            default:

                break;

        }

        return num;

    }

    @Override

    public String getType(Uri uri) {

        // TODO Auto-generated method stub

        Log.i("info", "getType");

        switch (uriMatcher.match(uri)) {

        case 1:

//          操作的数据类型为集合类型,返回值以vnd.android.cursor.dir/开头

//          eg:得到person表的所有数据

            return "vnd.android.cursor.dir/person";

        case 2:

//          操作的数据类型为非集合类型,返回值以vnd.android.cursor.item/开头

//          得到person表下面,每一条数据

            return "vnd.android.cursor.item/person";

        }

        return null;

    }

 

    @Override

    public Uri insert(Uri uri, ContentValues values) {

        // TODO Auto-generated method stub

        SQLiteDatabase db=dbHelper.getWritableDatabase();

        long id=db.insert("person", null, values);//id?

        if(id>-1){

            //构造新差入行的Uri

            Uri uri2=ContentUris.withAppendedId(contentUri, id);

            //通知所有的观察者,数据集已经发生了改变

            getContext().getContentResolver().notifyChange(uri2, null);

            return uri2;

        }

        return null;

    }

 

    @Override

    public boolean onCreate() {

        Log.i("info", "oncreate");

        dbHelper=new MyDbHelper(getContext(), "mydb.db", null, 1);

        return false;

    }

 

    @Override

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,

            String sortOrder) {

        // TODO Auto-generated method stub

        SQLiteDatabase db=dbHelper.getReadableDatabase();

        Cursor cursor = null;

        switch (uriMatcher.match(uri)) {

        case 1:

            cursor=db.query("person", 

                    null, //列的数组,null 代表所有的列

                    selection, selectionArgs, 

                    null, //分组

                    null,//having

                    sortOrder);

 

            break;

        case 2:

            long id=ContentUris.parseId(uri);

            if(selection==null){

                selection="id="+id;

            }else{

                selection="id=+"+id+"and ("+selection+")";

            }

            cursor=db.query("person", 

                    null, //列的数组,null 代表所有的列

                    selection, selectionArgs, 

                    null, //分组

                    null,//having

                    sortOrder);

            break;

        default:

            break;

        }

        return cursor;

    }

 

    @Override

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

        SQLiteDatabase db=dbHelper.getWritableDatabase();

        int num=0;//收影响的行数

        switch (uriMatcher.match(uri)) {

        case 1:

            num=db.update("person", values,selection,selectionArgs);

            break;

        case 2:

            long id=ContentUris.parseId(uri);

            if(selection==null){

                selection="id="+id;

            }else{

                selection="id=+"+id+"and ("+selection+")";

            }

            num=db.update("person", values,selection,selectionArgs);

            break;

        default:

            break;

        }

        return num;

    }

上面的代码定义了一个简单的contentprovider,并向外部提供了对数据库中person表的CURD方法。下边代码表明应用程序如何使用自定义的contentprovider

```‘
ContentResolver cr=getContentResolver();
//增加数据
ContentValues values=new ContentValues();
values.put("name", "Tom");
values.put("age", 22);
cr.insert(MyContentProvider.contentUri, values);
values.clear();
values.put("name", "Tony");
values.put("age", 25);
cr.insert(MyContentProvider.contentUri, values);
//查询所有数据
Uri uri
=Uri.parse("content://com.exam.demodata.utils.MyContentProvider/person/3");
// uri=ContentUris.withAppendedId(uri, 3);除了上边在URI中指定查询的id以外,还可以这种方式
Cursor cursor=cr.query(uri, null, null, null, null);
if(cursor.moveToFirst()){
do{
Log.i("info", "id="+cursor.getInt(0)+" name="+cursor.getString(1)+" age="+cursor.getInt(2));
}while(cursor.moveToNext());
//注意,这里使用do_while()循环
cursor.close();
}

 

 - xml中注册provider遇到的问题

首先看注册的代码:

<provider
android:name="com.exam.demodata.utils.MyContentProvider"
android:authorities="com.exam.demodata.utils.MyContentProvider"
android:exported="true"></provider>

注意到上面的注册,比起一般的注册多了一个exported属性;此时可能会出现如下警告:

Exported content providers can provide access to potentially sensitive data

解释及解决办法

 

> 1If you just want the content provider to be accessed internally from within your app, simply add **android:exported="false"**     into the node in the manifest.

设置为false的目的: The provider is not available to other applications. Set android:exported="false" to limit access to the provider to your applications.Only applications that have the same user ID (UID) as the provider will have access to it.

2Also if you are sure that you want to allow external access to your content provider and silence the warning add

**tools:ignore="ExportedContentProvider"**  into the node in the manifest.

e.g.
<provider
tools:ignore="ExportedContentProvider"
android:exported="true"
android:name="Contentprovider"
android:authorities="umb.con.apps.vid" />

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhwadezh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值