ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用。只有当需要在多个应用之间共享数据时才会用到ContentProvider。

多个应用共享数据时,如何区分是哪个应用中的那部分数据呢?

ContentProvider通过Uri标识具体某个应用的某些数据。当一个应用提供了ContentProvider向其他应用共享数据时,该应用在其ContentProvider中添加标识自己特定数据的Uri,然后其他应用想要获得这些数据时,则可以通过向ContentResolver接口的方法传入标识要访问的数据的Uri即可。

如应用B和应用C都向外提供数据,他们就需要在自己提供的ContentProvider中分别指明自己所能解析的Uri。应用A要访问应用B和应用C提供的数据,就需要使用ContentResolver接口,要向该接口的访问数据的方法中传入特定的Uri以区分是要访问应用B的数据,还是要访问应用C的数据。

应用之间共享数据需要用到的类和接口有:ContentProvider、ContentResolver、Uri、UriMatcher、ContentUris等。

下面一一学习这几个类和接口的简单使用:

1)ContentProvider:

该类是一个抽象类,要在自己应用中使用ContentProvider对象,需要自定义类继承ContentProvider类,并实现几个主要的抽象方法:

onCreate()方法: 其它应用第一次访问该ContentProvider时被调。

insert()方法:外部应用使用此方法添加数据。

delete()方法:外部应用使用此方法删除数据。

update  ()方法:外部应用使用此方法更新数据。

query()方法:外部应用使用此方法查询数据。

getType()方法: 主要用于匹配数据类型,返回当前Uri所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/自定义类型。数据属于非集合类型数据,应该返回vnd.android.cursor.item/自定义类型。

2)ContentResolver:

是一个接口,可以通过Context.getContentResolver()获取该接口的实例,当在自己应用中要访问别的应用ContentProvider提供的数据时,需要获取该接口的实例,然后调用该接口的insert()、update()、query()、delete()等方法,最终会调用对应ContentProvider中同名的方法,实现共享数据的增删改查操作。

3)Uri:

也是一个抽象类。

Uri标准的格式是:schema://主机名authority/path[/ID]

后面的ID部分根据访问需要,可能没有。

如:content://cn.csc.app1/student标识要访问的是cn.csc.app1所标识的应用中的student表。

ContentProvider中Uri的schema部分一般为content://

authority用来标识要访问的是哪个ContentProvider,通常用能唯一标识应用的包名作为authority。

path部分,则标识我们要访问的是哪些数据,如student表示我们要访问的是student表的数据。

若加上ID部分,如content://cn.csc.app1/student/10,一般被用来表示我们要访问的是student表中的id为10的那条数据。

uri中可以使用通配符:

*:表示匹配任意长度的字符串

#:表示匹配任意长度的数字串

如匹配任意表的uri可以表示为:content://cn.csc.app1/*

匹配student表中任意一条记录的uri:content://cn.csc.app1/student/#

常用到的是Uri中的一个静态方法:

parse()用来将字符串表示的uri解析为Uri对象。

4)UriMatcher:

Uri匹配的一个工具类,一般用在ContentProvider中:

一般使用常量NO_MATCH作为参数,构造UriMatcher对象,然后调用addURI()方法向该对象中添加URI,使用match()方法判断传入的Uri的匹配结果。

addURI()方法的参数说明:

authority:Uri中的authority用于标识是哪个ContentProvider

path:Uri中的path部分,标识要操作的是哪张表

code:用于设置当前添加的Uri的标识码,当使用match方法,传入一个Uri参数时,会将匹配到的Uri对应的code返回,以指明当前匹配到哪个Uri。

5)ContentUris:

一个实用的对Uri进行操作的工具类

parseId():用来获取传入的Uri中的Id部分

withAppendId():用于将传入的Uri和id拼接起来。

下面是实际编写ContentProvider的一个简单示例:

第一步:要先有一个数据库帮助类,以便于进行数据库增删改查操作

 package cn.csc.content_provider.db;

 import android.content.Context;

 import android.database.sqlite.SQLiteDatabase;

 import android.database.sqlite.SQLiteOpenHelper;

 import android.database.sqlite.SQLiteDatabase.CursorFactory;

 import android.util.Log;

 public class MySqliteHelper extends SQLiteOpenHelper {

       public static final String TAG = "MYSQLITEHELPER";

       public static final String CREATE_STUDENT = "create table t_student (" +

                  "id integer primary key, name varchar(20), " +

                  "gender varchar(10), age integer)";

       public static final String CREATE_TEACHER = "create table t_teacher(" +

                  "id integer primary key, name varchar(20))";

       public MySqliteHelper(Context context, String name, CursorFactory factory,

                  int version) {

            super(context, name, factory, version);

       }

       @Override

       public void onOpen(SQLiteDatabase db) {

            Log.i(TAG,"open db");

            super.onOpen(db);

       }

       @Override

       public void onCreate(SQLiteDatabase db) {

            db.execSQL(CREATE_STUDENT);

            db.execSQL(CREATE_TEACHER);

       }

       @Override

       public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

       }

 }

第二步:编写自己的ContentProvider类,继承自ContentProvider类,并实现主要的方法:

 1)编写MyContentProvider继承自ContentProvider类:

 public class MyContentProvider extends ContentProvider {

       @Override

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

            // TODO Auto-generated method stub

            return 0;

       }

       @Override

       public String getType(Uri uri) {

            // TODO Auto-generated method stub

            return null;

       }

       @Override

       public Uri insert (Uri uri, ContentValues values){

            // TODO Auto-generated method stub

            return null;

       }

       @Override

       public boolean onCreate() {

            // TODO Auto-generated method stub

            return false;

       }

       @Override

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

            // TODO Auto-generated method stub

            return null;

       }

       @Override

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

            // TODO Auto-generated method stub

            return 0;

       }

 }

2)注意,四大组件都需要在Manifest.xml文件中注册:

在Application节点中添加:

 <provider android:name="cn.csc.content_provider.MyContentProvider"

             android:authorities="cn.csc.content_provider"></provider>

3)为该类添加一个静态UriMatcher字段,用于后续工作中Uri的匹配工作,并通过静态代码块,添加能够匹配的Uri:

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

       private static final int STUDENT_DIR = 0;

       private static final int STUDENT_ITEM = 1;

       private static final int TEACHER_DIR = 2;

       private static final int TEACHER_ITEM = 3;

       static{

            matcher.addURI("cn.csc.content_provider", "t_student", STUDENT_DIR);

            matcher.addURI("cn.csc.content_provider", "t_student/#", STUDENT_ITEM);

            matcher.addURI("cn.csc.content_provider", "t_teacher", TEACHER_DIR);

            matcher.addURI("cn.csc.content_provider", "t_teacher/#", TEACHER_ITEM);

       }

4)实现父类中的几个抽象方法:

 @Override

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

            int cnt = -1;

            switch(matcher.match(uri)){

            case STUDENT_DIR:

                  cnt = db.delete("t_student", selection, selectionArgs);

                  break;

            case STUDENT_ITEM:

                  long id = ContentUris.parseId(uri);

                  cnt = db.delete("t_student", "id = ?", new String[]{id+""});

                  break;

            case TEACHER_DIR:

                  cnt = db.delete("t_teacher", selection, selectionArgs);

                  break;

            case TEACHER_ITEM:

                  long id1 = ContentUris.parseId(uri);

                  cnt = db.delete("t_teacher", "id = ?", new String[]{id1+""});

                  break;

            }

            return cnt;

       }

       @Override

       public String getType(Uri uri) {

            switch(matcher.match(uri)){

            case STUDENT_ITEM:

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

            case TEACHER_ITEM:

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

            case STUDENT_DIR:

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

            case TEACHER_DIR:

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

            }

            return null;

       }

       @Override

       public Uri insert (Uri uri, ContentValues values){

            switch(matcher.match(uri)){

            case STUDENT_DIR:

                  long id = db.insert("t_student", null, values);

                  return ContentUris.withAppendedId(uri, id);

            case TEACHER_DIR:

                  return ContentUris.withAppendedId(uri, db.insert("t_teacher", null, values));

            }

            return null;

       }

       @Override

       public boolean onCreate() {

            helper = new MySqliteHelper(getContext(), "students.db", null, 1);

            db = helper.getWritableDatabase();

            return true;

       }

       @Override

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

            Cursor cursor = null;

            switch (matcher.match(uri)) {

            case STUDENT_ITEM:

                  long id = ContentUris.parseId(uri);

                  cursor = db.query("t_student", projection, "id = ?", new String[]{id+""}, null, null, sortOrder);

                  break;

            case TEACHER_ITEM:

                  long id1 = ContentUris.parseId(uri);

                  cursor = db.query("t_teacher", projection, "id = ?", new String[]{id1+""}, null, null, sortOrder);

                  break;

            case STUDENT_DIR:

                  cursor = db.query("t_student", projection, selection, selectionArgs, null, null, sortOrder);

                  break;

            case TEACHER_DIR:

                  cursor = db.query("t_teacher", projection, selection, selectionArgs, null, null, sortOrder);

                  break;

            }

            return cursor;

       }

       @Override

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

            int cnt = -1;

            switch (matcher.match(uri)) {

            case STUDENT_ITEM:

                  long id = ContentUris.parseId(uri);

                  cnt = db.update("t_student", values, "id = ?", new String[]{id+""});

                  break;

            case TEACHER_ITEM:

                  long id1 = ContentUris.parseId(uri);

                  cnt = db.update("t_teacher", values, "id = ?", new String[]{id1+""});

                  break;

            case STUDENT_DIR:

                  cnt = db.update("t_student", values, selection, selectionArgs);

                  break;

            case TEACHER_DIR:

                  cnt = db.update("t_teacher", values, selection, selectionArgs);

                  break;

            }

            return cnt;

       }

5)新建一个项目,在其中通过ContentResolver访问该ContentProvider提供的数据:

 public class MyTest extends AndroidTestCase {

       public void testInsert(){

            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student");

            ContentValues values = new ContentValues();

            values.put("name", "dqrcsc");

            values.put("gender", "male");

            values.put("age", 24);

            Uri uri2 = getContext().getContentResolver().insert(uri, values);

            Log.i("Test",uri2.toString());

       }

       public void testUpdate(){

            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/2");

            ContentValues values = new ContentValues();

            values.put("name", "bbbb");

            values.put("gender", "female");

            values.put("age", 12);

            int i = getContext().getContentResolver().update(uri, values, null, null);

            Log.i("Test",i+"");

       }

       public void testQuery(){

            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/3");

            Cursor cursor = getContext().getContentResolver().query(uri, new String[]{"id","name","gender","age"}, null, null, null);

            while(cursor != null && cursor.moveToNext()){

                  Log.i("Test",cursor.getString(0)+","+cursor.getString(1)+","+cursor.getString(2)+","+cursor.getString(3));

            }

       }

       public void testQueryAll(){

            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student");

            Cursor cursor = getContext().getContentResolver().query(uri, new String[]{"id","name","gender","age"}, null, null, null);

            while(cursor != null && cursor.moveToNext()){

                  Log.i("Test",cursor.getString(0)+","+cursor.getString(1)+","+cursor.getString(2)+","+cursor.getString(3));

            }

       }

       public void testDelete(){

            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/6");

            int i = getContext().getContentResolver().delete(uri, null, null);

            Log.i("Test",i+"");

       }

 }

以上,就是ContentProvider的简单使用。

android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用的更多相关文章

  1. android菜鸟学习笔记13----Android控件(二) 自定义控件简单示例

    有时候,可能觉得系统提供的控件太丑,就会需要自定义控件来实现自己想要的效果. 以下主要参考<第一行代码> 1.自定义一个标题栏: 系统自带的标题栏很丑,且没什么大的作用,所以我们之前会在o ...

  2. android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人

    要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...

  3. android菜鸟学习笔记22----ContentProvider(二)ContentObserver的简单使用

    现在有这样一个应用A通过ContentProvider提供自己的数据给其他应用,应用B通过ContentResolver获取应用A中提供的数据,并将其展示在ListView中,而应用C通过Conten ...

  4. android菜鸟学习笔记8----Activity(一)

    Activity是android应用程序中重要的组件之一,常听到的android四大组件是Activity.Service.BroadcastReceiver和ContentProvider.它间接继 ...

  5. android菜鸟学习笔记30----Android使用百度地图API(一)准备工作及在应用中显示地图

    1.准备工作: 百度地图API是免费开放的,但是需要申请API Key: 1)先注册一个百度开发者帐号 2)进入百度开放服务平台http://developer.baidu.com/ 3)进入LBS云 ...

  6. android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结

    常见的向用户发送提示信息的方式有3种,分别为: 1)发送Toast信息 2)弹出对话框 3)发送通知 总结如下: 方式1:发送Toast信息: 这种方式最简单,在之前的学习中多次使用过.Toast是在 ...

  7. android菜鸟学习笔记27----Fragment的简单使用

    1.Fragment的生命周期: 简单在新建一个MyFragment继承自Fragment,重写各个生命周期回调方法,各个方法中直接输出标识相关函数被调用的信息. 重写MainActivity的各个生 ...

  8. android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据

    主要是基于HTTP协议与服务端进行交互. 涉及到的类和接口有:URL.HttpURLConnection.HttpClient等 URL: 使用一个String类型的url构造一个URL对象,如: U ...

  9. android菜鸟学习笔记20----Android数据存储(四))Android数据库操作

    Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...

随机推荐

  1. Xml解析(Dom解析xml)

    xml四种解析方式: DOM 平台无关的官方解析方式 优点:形成了树结构,直观好理解,代码更易编写 解析过程中树结构保留在内存中,方便修改 缺点:当xml文件较大时,对内存耗费比较大,容易影响解析性能 ...

  2. 【Hadoop】Hadoop 机架感知配置、原理

    Hadoop机架感知 1.背景 Hadoop在设计时考虑到数据的安全与高效,数据文件默认在HDFS上存放三份,存储策略为本地一份, 同机架内其它某一节点上一份,不同机架的某一节点上一份. 这样如果本地 ...

  3. netty handle处理流程

    server handlerAdded server channelRegistered server channelActive server read server channelInactive ...

  4. 模仿 BootstrapValidator 自制 模块化 表单验证

    index.html : <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  5. vue-router 响应路由参数的变化

    提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用.因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效.不过,这也意味着组件的生命周 ...

  6. xpinyin-函数返回多个值-lambda匿名函数-列表生成式-三元表达式

    import xpinyinp=xpinyin.Pinyin() #实例化print(p.get_pinyin('小白','')) 函数返回多个值:1.函数如果返回多个值的话,它会把这几个值放到一个元 ...

  7. apt-update 更新失败 (无法连接到ubuntu服务器)

    解决方法: 找一个可以更新的系统,拷贝里面的sources.list文件,并将原系统的sources.list进行备份.

  8. C# string[ ][ ] 与string[,]

    1.string[][] 是一维数组,数组中的元素是string[],相当于锯齿数组 例如:string[][] arrar = new string[][] {                  n ...

  9. python--pipe

    1.pipe 除了使用队列外,还可以使用管道在进程间执行消息传递 pipe([]duplex) 在进程间创建一条管道,并返回元组(conn1,conn2),其中conn1和conn2是表示管道两端的C ...

  10. AIX 安装标准

    文件夹 一.网卡需求 二.光纤卡需求 三.磁盘需求 四.主机文件系统需求 五.主机名命名规范 六.安装设置规范 七.參数改动规范 八.时钟同步设置 九.rootvg做镜像 十.AIX系统安全加固 一. ...