开发者社区> sealin> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Android中ContentProvider组件详解

简介:
+关注继续查看

一.Android四大组件

Android四大组件是Activity, Service, Content Provider,Broadcast Receiver

Activity作为程序界面,直接与用户交互

Service运行在后台,没有界面,完成特定的功能

ContentProvider维护应用数据,方便应用本身或其它应用访问

Broadcast Receiver提供异步广播消息接收机制,便于各应用/组件进行交互

二.什么是ContentProvider

        ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。

1.ContentProvider
        Android提供了一些主要数据类型的ContentProvider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些Android提供的ContentProvider。通过获得这些ContentProvider可以查询它们包含的数据,当然前提是已获得适当的读取权限。
主要方法:

<span style="font-size:12px;">public boolean onCreate() 在创建ContentProvider时调用
public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor
public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中
public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据
public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据
public String getType(Uri) 用于返回指定的Uri中的数据的MIME类型
*如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头。
例如:要得到所有person记录的Uri为content://contacts/person,那么返回的MIME类型字符串为"vnd.android.cursor.dir/person"。
*如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。
例如:要得到id为10的person记录的Uri为content://contacts/person/10,那么返回的MIME类型字符串应为"vnd.android.cursor.item/person"。</span>

2.ContentResolver
        当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

<span style="font-size:12px;">ContentResolver cr = getContentResolver();</span>  
ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。

<span style="font-size:12px;">public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。
public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查</span>询指定Uri的ContentProvider。

3.Uri

        Uri 代表了要操作的数据,Uri 主要包含了两部分信息:1、需要操作的
ContentProvider;2、对ContentProvider中的什么数据进行操作。一个Uri由以
下几部分组成:

       ContentProvider的scheme已经由Android所规定,scheme为content://。
主机名(authorities)用于唯一标识这个ContentProvider,外部调用者可以根据
它找到对应的内容提供者(ContentProvider)。
路径(Path)可以用来表示我们要操作的数据,路径的构建应该根据业务而定,
如下:
要操作Person表中ID 为10的记录,可以构建这样的路径:/person/id/10,也
可以为/prson/10,构建什么样的路径需要与UriMatcher中注册的匹配Uri相一
致。例如:/person/id/10,那么匹配Uri需要也需要带id 为/preson/id/#,否则
可以写成/person/10.
要操作person表中的所有记录,可以这样构建路径:/person
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法。如下:
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")

三、UriMatcher类使用介绍

        因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:

<span style="font-size:12px;color:#000000;">//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码   
UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);   
//如果match()方法匹配content:  
//com.ljq.provider.personprovider/person路径,返回匹配码为1,匹配Uri注册如下:   
sMatcher.addURI("com.ljq.provider.personprovider", person", 1);  
//添加需要匹配uri,如果匹配就会返回匹配码   
//如果match()方法匹配content://com.ljq.provider.personprovider/person/230路径,返回匹配码为2,配Uri注册如下:   
sMatcher.addURI("com.ljq.provider.personprovider", "person/#", 2);  
//#号为通配符   
//传入Uri,进行匹配   
switch (sMatcher.match(Uri.parse("content://com.ljq.provider.personprovider/person/10"))) {    
     case 1   
       break;   
     case 2   
       break;   
     default://不匹配   
       break;   
 }   </span>
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)对输入的uri进
匹配,如果匹配正确就返回匹配码,匹配码是addUri()方法传入的第三个
数,假设匹配content://com.ljq.provider.personprovider/person 路径,返回
匹配码为1。

四、ContentUris介绍

ContentUris用于操作Uri后面的ID 部分,它有两个实用的方法:
WithAppendedId(uri, id)用于为uri路径加上id 部分,如下:

<span style="font-size:12px;color:#000000;">Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")   
Uri resultUri = ContentUris.withAppendedId(uri, 10);    
//生成后的Uri为:content://com.ljq.provider.personprovider/person/10   
parseId(uri)用于从路径中获取Id,如下:   
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")   
long personid = ContentUris.parseId(uri);  
//获取的结果为:10</span>

五、监听ContentProvider中数据的变化

        如果ContentProvider的访问者需要知道ContentProvider中数据发生变化,可以在ContentProvider中数据发生变化时调用getContentResovler().notifyChange(uri, null)来通知注册在此uri上的访问者,如下:
<span style="font-size:12px;color:#000000;">public class PersonContentProvider extends ContentProvider {   
     public Uri insert(Uri uri, ContentValues values) {   
        db.insert("person", "personid", values);   
        getContext().getContentResolver().notifyChange(uri, null);   
     }   
 }   </span>
        如果ContentProvider 的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用Uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法,如下:
<span style="font-size:12px;color:#000000;">getContentResolver().registerContentObserver(Uri.parse("content://com.ljq.providers.personprovider/person"),   
       true, new PersonObserver(new Handler()));   
public class PersonObserver extends ContentObserver{   
   public PersonObserver(Handler handler) {   
      super(handler);   
   }   
   public void onChange(boolean selfChange) {   
      //此处可以进行相应的业务处理   
   }   
}   </span>

六、具体实例
<span style="font-size:12px;color:#000000;">public class FirstContentProvider extends ContentProvider {  
      
        // UriMatcher类主要用来匹配Uri  
        private static final UriMatcher uriMatcher = new UriMatcher(  
                UriMatcher.NO_MATCH);  
        private MySqlite mysqlite;  
        static {  
            // 注册向外部程序提供的Uri  
            uriMatcher.addURI(UserInfo.AUTOR, "userinfo", 1);  
            uriMatcher.addURI(UserInfo.AUTOR, "userinfoall", 2);  
        }  
        //删除数据  
        @Override  
        public int delete(Uri uri, String selection, String[] selectionArgs) {  
            int number = 0;  
            if (uriMatcher.match(uri) == 1) {  
                // 根据条件删除数据,并获取删除的行数  
                number = mysqlite.getReadableDatabase().delete("user_info",  
                        selection, selectionArgs);  
            }  
            // 通知数据已经改变  
            getContext().getContentResolver().notifyChange(uri, null);  
            return number;  
        }  
      
        @Override  
        public String getType(Uri uri) {  
      
            return null;  
        }  
        //插入数据  
        @Override  
        public Uri insert(Uri uri, ContentValues values) {  
            String name = values.getAsString(UserInfo.User.NAME).toString();  
            String age = values.getAsInteger(UserInfo.User.AGE).toString();  
            String maxId = "select max(id) id from user_info";  
            Cursor cursor = mysqlite.getReadableDatabase().rawQuery(maxId, null);  
            cursor.moveToFirst();  
            int userid = cursor.getInt(0) + 1;  
            if (uriMatcher.match(uri) == 1) {  
      
                mysqlite.getWritableDatabase().execSQL(  
                        "insert into user_info values(?,?,?)",  
                        new String[] { String.valueOf(userid), name, age });  
            }  
            return uri;  
        }  
      
        // 连接数据库  
        @Override  
        public boolean onCreate() {  
            mysqlite = new MySqlite(getContext(), "userinfo.db", null, 1);  
            return true;  
        }  
        //查询数据  
        @Override  
        public Cursor query(Uri uri, String[] projection, String selection,  
                String[] selectionArgs, String sortOrder) {  
            SQLiteDatabase sqlite = mysqlite.getReadableDatabase();  
            String str = "select name,age from user_info";  
            if (uriMatcher.match(uri) == 1) {  
                str += " where " + selection;  
            }  
            Cursor cursor = sqlite.rawQuery(str, selectionArgs);  
            return cursor;  
        }  
        //修改数据  
        @Override  
        public int update(Uri uri, ContentValues values, String selection,  
                String[] selectionArgs) {  
            SQLiteDatabase sqlite = mysqlite.getReadableDatabase();  
            int number = 0;  
            if (uriMatcher.match(uri) == 1) {  
                number = sqlite.update("user_info", values, selection,  
                        selectionArgs);  
            }  
            return number;  
        }  
      
    }  </span>


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
ContentProvider
构建content URI public class TaskContract { /* COMPLETED (1) Add content provider constants to the Contract Clients need to know how to access the task data, and it's your job to provide these content URI's for the path to that data: 1) Content authority, 2) Base content
42 0
Android中contentProvider的用途
使用内容供应商共享数据 如果直接访问磁盘文件(SDCard|File|SQLite数据库|首选项),需要很多底层的交互细节,但该种方式,只使用url即可对应用程序进行访问,并统一了数据访问方式。 public class PersonContentProvider extends ContentProvider{ //在该生命周期中才能正确得到Content对象。 public
1352 0
+关注
sealin
学无止境
348
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载