• 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
     import cn.itcast.service.DBOpenHelper;
     import android.content.ContentProvider;
     import android.content.ContentUris;
     import android.content.ContentValues;
     import android.content.UriMatcher;
     import android.database.Cursor;
     import android.database.sqlite.SQLiteDatabase;
     import android.net.Uri;
     
     public class PersonProvider extends ContentProvider {
         private DBOpenHelper dbOpenHelper;
         //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
         private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
         private static final int PERSONS = 1;
         private static final int PERSON = 2;
         static{
             //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
             MATCHER.addURI("cn.itcast.providers.personprovider", "person", PERSONS);
             //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
             MATCHER.addURI("cn.itcast.providers.personprovider", "person/#", PERSON);
         }   
         //删除person表中的所有记录   /person
     //删除person表中指定id的记录 /person/10
         @Override
         public int delete(Uri uri, String selection, String[] selectionArgs) {
             SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
             int count = 0;
             switch (MATCHER.match(uri)) {
             case PERSONS:
                 count = db.delete("person", selection, selectionArgs);
                 return count;
                
             case PERSON:
                 long id = ContentUris.parseId(uri);
                 String where = "personid="+ id;
                 if(selection!=null && !"".equals(selection)){
                     where = selection + " and " + where;
                 }
                 count = db.delete("person", where, selectionArgs);
                 return count;
                
             default:
                 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
             }
         }
     
         @Override
         public String getType(Uri uri) {//返回当前操作的数据的mimeType
             switch (MATCHER.match(uri)) {
             case PERSONS:    //多条数据       
                 return "vnd.android.cursor.dir/person";
                
             case PERSON:    //单条数据       
                 return "vnd.android.cursor.item/person";
                
             default:
                 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
             }
         }
     
         @Override
         public Uri insert(Uri uri, ContentValues values) {// /person
             SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
             switch (MATCHER.match(uri)) {
             case PERSONS:
                 long rowid = db.insert("person", "name", values);
                 //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
                 Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增记录的Uri
     //当ContentProvider中的数据发生变化时可以向其用户发出通知,第一个参数为uri,说明是person表的uri,不是单条记录的uri
                 this.getContext().getContentResolver().notifyChange(uri, null);
                 return insertUri;
     
             default://不匹配
                 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
             }
         }
     
         @Override
         public boolean onCreate() {
             this.dbOpenHelper = new DBOpenHelper(this.getContext());
             return false;
         }
         //查询person表中的所有记录   /person
     //查询person表中指定id的记录 /person/10
         @Override
         public Cursor query(Uri uri, String[] projection, String selection,
                 String[] selectionArgs, String sortOrder) {
             SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
             switch (MATCHER.match(uri)) {
             case PERSONS:
                 return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
                
             case PERSON:
                 long id = ContentUris.parseId(uri);
                 String where = "personid="+ id;
                 if(selection!=null && !"".equals(selection)){
                     where = selection + " and " + where;
                 }
                 return db.query("person", projection, where, selectionArgs, null, null, sortOrder);
                
             default:
                 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
             }
         }
        
         //更新person表中的所有记录   /person
     //更新person表中指定id的记录 /person/10
         @Override
         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
             SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
             int count = 0;
             switch (MATCHER.match(uri)) {
             case PERSONS:
                 count = db.update("person", values, selection, selectionArgs);
                 return count;
                
             case PERSON:
                 //parseId(uri)方法用于从路径中获取ID部分:获取的结果为:10
                 long id = ContentUris.parseId(uri);
                 String where = "personid="+ id;
                 //如果外面传进来的条件不为空,而且不为空字符串
                 if(selection!=null && !"".equals(selection)){
                     //外面的条件加自己的条件
                     where = selection + " and " + where;
                 }
                 count = db.update("person", values, where, selectionArgs);
                 return count;
                
             default:
                 throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());
             }
         }
     
     }

    AndroidMainFest.xml代码

    View Code
     <?xml version="1.0" encoding="utf-8"?>
     <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="cn.itcast.db"
           android:versionCode="1"
           android:versionName="1.0">
         <application android:icon="@drawable/icon" android:label="@string/app_name">
              <uses-library android:name="android.test.runner" />
             <activity android:name=".MainActivity"
                       android:label="@string/app_name">
                 <intent-filter>
                     <action android:name="android.intent.action.MAIN" />
                     <category android:name="android.intent.category.LAUNCHER" />
                 </intent-filter>
             </activity>
             <provider android:name=".PersonProvider" android:authorities="cn.itcast.providers.personprovider"/>
         </application>
         <uses-sdk android:minSdkVersion="8" />
     <instrumentation android:name="android.test.InstrumentationTestRunner"
       android:targetPackage="cn.itcast.db" android:label="Tests for My App" />
     </manifest>

    另一个应用程序调用ContentProvider

    View Code
     import android.content.ContentResolver;
     import android.content.ContentValues;
     import android.database.Cursor;
     import android.net.Uri;
     import android.test.AndroidTestCase;
     import android.util.Log;
     
     public class AccessContentProviderTest extends AndroidTestCase {
         private static final String TAG = "AccessContentProviderTest";
        
         /**
          * 往内容提供者添加数据
          * @throws Throwable
     */
         public void testInsert() throws Throwable{
             ContentResolver contentResolver = this.getContext().getContentResolver();
             Uri insertUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
             ContentValues values = new ContentValues();
             values.put("name", "zhangxiaoxiao");
             values.put("amount", 90);
             Uri uri = contentResolver.insert(insertUri, values);
             Log.i(TAG, uri.toString());
         }
     
         /**
          * 更新内容提供者中的数据
          * @throws Throwable
     */
         public void testUpdate() throws Throwable{
             ContentResolver contentResolver = this.getContext().getContentResolver();
             Uri updateUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
             ContentValues values = new ContentValues();
             values.put("name", "lili");
             contentResolver.update(updateUri, values, null, null);
         }
        
         /**
          * 从内容提供者中删除数据
          * @throws Throwable
     */
         public void testDelete() throws Throwable{
             ContentResolver contentResolver = this.getContext().getContentResolver();
             Uri deleteUri = Uri.parse("content://cn.itcast.providers.personprovider/person/1");
             contentResolver.delete(deleteUri, null, null);
         }
        
         /**
          * 获取内容提供者中的数据
          * @throws Throwable
     */
         public void testFind() throws Throwable{
             ContentResolver contentResolver = this.getContext().getContentResolver();
             Uri selectUri = Uri.parse("content://cn.itcast.providers.personprovider/person");
             Cursor cursor = contentResolver.query(selectUri, null, null, null, "personid desc");
             while(cursor.moveToNext()){
                 int id = cursor.getInt(cursor.getColumnIndex("personid"));
                 String name = cursor.getString(cursor.getColumnIndex("name"));
                 int amount = cursor.getInt(cursor.getColumnIndex("amount"));
                 Log.i(TAG, "id="+ id + ",name="+ name+ ",amount="+ amount);
             }
         }
     }

  • 相关阅读:
    【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
    【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
    【转】Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果
    android Touch事件传递小结
    【转】七、android图片特效处理之光晕效果
    【转】六、android图片特效处理之图片叠加
    【转】五、android图片特效处理之光照效果
    【转】四、android图像特效处理之底片效果
    【转】三、android图片特效处理之锐化效果
    linux命令简写与全写
  • 原文地址:https://www.cnblogs.com/fx2008/p/3137985.html
Copyright © 2020-2023  润新知