• ContentProvider


    ContentProvider简介

    ContentProvider(数据提供者)是在应用程序间共享数据的一种接口机制
    ContentProvider提供了更为高级的数据共享方法,应用程序可以指定需要共享的数据,而其他应用程序则可以在不知数据来源、路径的情况下,对共享数据进行查询、添加、删除和更新等操作
    许多Android系统的内置数据也通过ContentProvider提供给用户使用,例如通讯录、音视频文件和图像文件等
    在创建ContentProvider时,需要首先使用数据库、文件系统或网络实现底层存储功能,然后在继承ContentProvider的类中实现基本数据操作的接口函数,包括添加、删除、查找和更新等功能
    调用者不能够直接调用ContentProvider的接口函数,而需要使用ContentResolver对象,通过URI间接调用ContentProvider。

    使用ContentProvider可以在不同的应用程序之间共享数据。 它为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。

    ContentProvider不管底层数据的实际存储方式,对外统一使用表的形式来组织数据 。

    URI的简介

    Uri代表了要操作的数据,它为系统的每一个资源给其一个名字,比方说通话记录。每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。 

     URI的格式

    A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
     B:URI 的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称; "content://hx.android.text.myprovider"
    C:路径,通俗的讲就是你要操作的数据库中表的名字;"content://hx.android.text.myprovider/tablename"
    D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id

    路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下: • 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10 • 要操作contact表中id为10的记录的name字段, contact/10/name • 要操作contact表中的所有记录,可以构建这样的路径:/contact
    要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下: 要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name
    如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下: Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")

    UriMatcher

    因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供UriMatcher ,用于匹配Uri,用法如下:   
    1.首先把你需要匹配Uri路径全部给注册上,如:
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);
       uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);
    2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码.
    //如果match()匹配路径,返回匹配码为1
     content://com.changcheng.sqlite.provider.contactprovider/contact
    //如果match()匹配路径,返回匹配码为2
    content://com.changcheng.sqlite.provider.contactprovider/contact/23

    因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
    UriMatcher类用于匹配Uri,它的用法如下:
    首先第一步把你需要匹配Uri路径全部给注册上,如下:
    //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
    UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
    sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
    //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
    sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
    switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
       case 1
        break;
       case 2
        break;
       default://不匹配
        break;
    }
    注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1

     ContentUris类

    ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
    withAppendedId(uri, id)用于为路径加上ID部分:
    Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
    Uri resultUri = ContentUris.withAppendedId(uri, 10);
    //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10

    parseId(uri)方法用于从路径中获取ID部分:
    Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
    long personid = ContentUris.parseId(uri);//获取的结果为:10

    ContentProvider的编程方法

    程序开发人员通过继承ContentProvider类可以创建一个新的数据提供者,过程可以分为三步
    1.继承ContentProvider,并重载六个函数
    public boolean onCreate()
    该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应用第一次访问它时才会被创建。
    public Uri insert(Uri uri, ContentValues values)
    该方法用于供外部应用往ContentProvider添加数据。
    public int delete(Uri uri, String selection, String[] selectionArgs)
    该方法用于供外部应用从ContentProvider删除数据。
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    该方法用于供外部应用更新ContentProvider中的数据。
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    该方法用于供外部应用从ContentProvider中获取数据。
    public String getType(Uri uri)
    该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。

    2.声明CONTENT_URI,实现UriMatcher
    3.注册ContentProvider  AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:

    <application android:icon="@drawable/icon" android:label="@string/app_name">
     <provider android:name = ".PeopleProvider"
       android:authorities = "edu.hrbeu.peopleprovider"/>
    </application>

    注意:一旦应用继承了ContentProvider类,后面我们就会把这个应用称为ContentProvider(内容提供者)。

    ContentResolver的编程方法

    使用ContentProvider是通过Android组件都具有的ContentResolver对象,通过URI进行数据操作
    程序开发人员只需要知道URI和数据集的数据格式,则可以进行数据操作,解决不同应用程序之间的数据共享问题
    每个Android组件都具有一个ContentResolver对象,获取ContentResolver对象的方法是调用getContentResolver()函数

    使用ContentResolver操作ContentProvider中的数据

    当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
    public Uri insert(Uri uri, ContentValues values)
    该方法用于往ContentProvider添加数据。
    public int delete(Uri uri, String selection, String[] selectionArgs)
    该方法用于从ContentProvider删除数据。
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    该方法用于更新ContentProvider中的数据。
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    该方法用于从ContentProvider中获取数据。

    这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。

    使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作
    ContentResolver resolver =  getContentResolver();
    Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
    //添加一条记录
    ContentValues values = new ContentValues();
    values.put("name", "itcast");
    values.put("age", 25);
    resolver.insert(uri, values);  
    //获取person表中所有记录
    Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
    while(cursor.moveToNext()){
     Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));
    }
    //把id为1的记录的name字段值更改新为liming
    ContentValues updateValues = new ContentValues();
    updateValues.put("name", "liming");
    Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
    resolver.update(updateIdUri, updateValues, null, null);
    //删除id为2的记录
    Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
    resolver.delete(deleteIdUri, null, null);

    当ContentProvider中的数据发生变化时可以向其用户发出通知

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

    具体一个例子代码:

    View Code
      1 import cn.itcast.service.DBOpenHelper;
    2 import android.content.ContentProvider;
    3 import android.content.ContentUris;
    4 import android.content.ContentValues;
    5 import android.content.UriMatcher;
    6 import android.database.Cursor;
    7 import android.database.sqlite.SQLiteDatabase;
    8 import android.net.Uri;
    9
    10 public class PersonProvider extends ContentProvider {
    11 private DBOpenHelper dbOpenHelper;
    12 //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
    13 private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    14 private static final int PERSONS = 1;
    15 private static final int PERSON = 2;
    16 static{
    17 //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
    18 MATCHER.addURI("cn.itcast.providers.personprovider", "person", PERSONS);
    19 //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
    20 MATCHER.addURI("cn.itcast.providers.personprovider", "person/#", PERSON);
    21 }
    22 //删除person表中的所有记录 /person
    23 //删除person表中指定id的记录 /person/10
    24 @Override
    25 public int delete(Uri uri, String selection, String[] selectionArgs) {
    26 SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    27 int count = 0;
    28 switch (MATCHER.match(uri)) {
    29 case PERSONS:
    30 count = db.delete("person", selection, selectionArgs);
    31 return count;
    32
    33 case PERSON:
    34 long id = ContentUris.parseId(uri);
    35 String where = "personid="+ id;
    36 if(selection!=null && !"".equals(selection)){
    37 where = selection + " and " + where;
    38 }
    39 count = db.delete("person", where, selectionArgs);
    40 return count;
    41
    42 default:
    43 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
    44 }
    45 }
    46
    47 @Override
    48 public String getType(Uri uri) {//返回当前操作的数据的mimeType
    49 switch (MATCHER.match(uri)) {
    50 case PERSONS: //多条数据
    51 return "vnd.android.cursor.dir/person";
    52
    53 case PERSON: //单条数据
    54 return "vnd.android.cursor.item/person";
    55
    56 default:
    57 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
    58 }
    59 }
    60
    61 @Override
    62 public Uri insert(Uri uri, ContentValues values) {// /person
    63 SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    64 switch (MATCHER.match(uri)) {
    65 case PERSONS:
    66 long rowid = db.insert("person", "name", values);
    67 //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
    68 Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增记录的Uri
    69 //当ContentProvider中的数据发生变化时可以向其用户发出通知,第一个参数为uri,说明是person表的uri,不是单条记录的uri
    70 this.getContext().getContentResolver().notifyChange(uri, null);
    71 return insertUri;
    72
    73 default://不匹配
    74 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
    75 }
    76 }
    77
    78 @Override
    79 public boolean onCreate() {
    80 this.dbOpenHelper = new DBOpenHelper(this.getContext());
    81 return false;
    82 }
    83 //查询person表中的所有记录 /person
    84 //查询person表中指定id的记录 /person/10
    85 @Override
    86 public Cursor query(Uri uri, String[] projection, String selection,
    87 String[] selectionArgs, String sortOrder) {
    88 SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
    89 switch (MATCHER.match(uri)) {
    90 case PERSONS:
    91 return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
    92
    93 case PERSON:
    94 long id = ContentUris.parseId(uri);
    95 String where = "personid="+ id;
    96 if(selection!=null && !"".equals(selection)){
    97 where = selection + " and " + where;
    98 }
    99 return db.query("person", projection, where, selectionArgs, null, null, sortOrder);
    100
    101 default:
    102 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
    103 }
    104 }
    105
    106 //更新person表中的所有记录 /person
    107 //更新person表中指定id的记录 /person/10
    108 @Override
    109 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    110 SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    111 int count = 0;
    112 switch (MATCHER.match(uri)) {
    113 case PERSONS:
    114 count = db.update("person", values, selection, selectionArgs);
    115 return count;
    116
    117 case PERSON:
    118 //parseId(uri)方法用于从路径中获取ID部分:获取的结果为:10
    119 long id = ContentUris.parseId(uri);
    120 String where = "personid="+ id;
    121 //如果外面传进来的条件不为空,而且不为空字符串
    122 if(selection!=null && !"".equals(selection)){
    123 //外面的条件加自己的条件
    124 where = selection + " and " + where;
    125 }
    126 count = db.update("person", values, where, selectionArgs);
    127 return count;
    128
    129 default:
    130 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
    131 }
    132 }
    133
    134 }

    AndroidMainFest.xml代码

    View Code
     1 <?xml version="1.0" encoding="utf-8"?>
    2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    3 package="cn.itcast.db"
    4 android:versionCode="1"
    5 android:versionName="1.0">
    6 <application android:icon="@drawable/icon" android:label="@string/app_name">
    7 <uses-library android:name="android.test.runner" />
    8 <activity android:name=".MainActivity"
    9 android:label="@string/app_name">
    10 <intent-filter>
    11 <action android:name="android.intent.action.MAIN" />
    12 <category android:name="android.intent.category.LAUNCHER" />
    13 </intent-filter>
    14 </activity>
    15 <provider android:name=".PersonProvider" android:authorities="cn.itcast.providers.personprovider"/>
    16 </application>
    17 <uses-sdk android:minSdkVersion="8" />
    18 <instrumentation android:name="android.test.InstrumentationTestRunner"
    19 android:targetPackage="cn.itcast.db" android:label="Tests for My App" />
    20 </manifest>

    另一个应用程序调用ContentProvider

    View Code
     1 import android.content.ContentResolver;
    2 import android.content.ContentValues;
    3 import android.database.Cursor;
    4 import android.net.Uri;
    5 import android.test.AndroidTestCase;
    6 import android.util.Log;
    7
    8 public class AccessContentProviderTest extends AndroidTestCase {
    9 private static final String TAG = "AccessContentProviderTest";
    10
    11 /**
    12 * 往内容提供者添加数据
    13 * @throws Throwable
    14 */
    15 public void testInsert() throws Throwable{
    16 ContentResolver contentResolver = this.getContext().getContentResolver();
    17 Uri insertUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
    18 ContentValues values = new ContentValues();
    19 values.put("name", "zhangxiaoxiao");
    20 values.put("amount", 90);
    21 Uri uri = contentResolver.insert(insertUri, values);
    22 Log.i(TAG, uri.toString());
    23 }
    24
    25 /**
    26 * 更新内容提供者中的数据
    27 * @throws Throwable
    28 */
    29 public void testUpdate() throws Throwable{
    30 ContentResolver contentResolver = this.getContext().getContentResolver();
    31 Uri updateUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
    32 ContentValues values = new ContentValues();
    33 values.put("name", "lili");
    34 contentResolver.update(updateUri, values, null, null);
    35 }
    36
    37 /**
    38 * 从内容提供者中删除数据
    39 * @throws Throwable
    40 */
    41 public void testDelete() throws Throwable{
    42 ContentResolver contentResolver = this.getContext().getContentResolver();
    43 Uri deleteUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
    44 contentResolver.delete(deleteUri, null, null);
    45 }
    46
    47 /**
    48 * 获取内容提供者中的数据
    49 * @throws Throwable
    50 */
    51 public void testFind() throws Throwable{
    52 ContentResolver contentResolver = this.getContext().getContentResolver();
    53 Uri selectUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
    54 Cursor cursor = contentResolver.query(selectUri, null, null, null, "personid desc");
    55 while(cursor.moveToNext()){
    56 int id = cursor.getInt(cursor.getColumnIndex("personid"));
    57 String name = cursor.getString(cursor.getColumnIndex("name"));
    58 int amount = cursor.getInt(cursor.getColumnIndex("amount"));
    59 Log.i(TAG, "id="+ id + ",name="+ name+ ",amount="+ amount);
    60 }
    61 }
    62 }


    这个app潮流公众帐号主要是推荐给手机用户最近最潮的软件,让大家随时跟上时尚。我们会提供给你们最好的服务,喜欢我们就帮我们推荐吧!

  • 相关阅读:
    BooStrap4文档摘录: 1. Layout
    PistgreSQL9.6手册(基础摘录)
    HTML 5与CSS 3权威指南(第3版·上册)
    Excel PPT 2013办公应用从入门到精通
    EclipseWTPWeb应用开发
    Photoshop移动UI设计实用教程(第2版)
    高手速成:EDIUS专业级视频与音频制作从入门到精通
    黑客攻防从入门到精通
    利用Python进行数据分析(原书第2版)
    Linux二进制分析
  • 原文地址:https://www.cnblogs.com/shaoyangjiang/p/2404010.html
Copyright © 2020-2023  润新知