• ContentProvider


    一、标注

      转载自http://www.cnblogs.com/cxcco/archive/2012/01/07/2315711.html,尊重原创!

    二、正文

      今天内容是ContentProvider——如果做过电话薄应用程序的人肯定都用过这个类,那ContentProvider到底是个什么东西,有什么用,如何用呢?

      1、  ContentProvider是个啥?

        ContentProvider——内容提供者。它是一个类,这个类主要是对Android系统中进行共享的数据进行包装,并提供了一组统一的访问接口供其他程序调用。这些被共享的数据,可以使系统自己的也可以使我们个人应用程序中的数据。

      2、  为什么要有ContentProvider这个类?

        在Android中,数据的存储有很多种方式,最常用的就是SQLite和XML文件方式。在不同的应用程序间,其实数据是不能直接被相互访问和操作的,在这种情况下,ContentProvider很好的被用来解决了不同应用程序间数据共享的问题。

        其实在Android系统中,已经为我们提供了许多ContentProvider,如:Contacts、Browser、CallLog、Settings等等。那么,Android系统中提供了这么多的ContentProvider,另外还有我们自己公开的共享数据,我们在写程序的时候,怎么才能让我们的应用程序知道去哪儿取、如何取这些数据呢?我们自然的会想到URI。

      3、  URI是个啥?在ContentProvider中有什么用处?URI中的几个方法。

        URI(Uniform Resource Identifier)——统一资源定位符,URI在ContentProvider中代表了要操做的数据。

        在Android系统中通常的URI格式为:content://LiB.cprovider.myprovider.Users/User/21

        在万维网访问时通常用的URI格式为:http://www.XXXX.com/AAA/123

      • content://——schema,这个是Android中已经定义好的一个标准。我个人一直认为这和我们的http://有异曲同工之妙,都是代表的协议。
      • LiB.cprovider.myprovider.Users——authority(主机名),用于唯一标识这个ContentProvider,外部调用者通过这个authority来找到它。相当于www.XXXX.com,代表的是我们ContentProvider所在的”域名”,这个”域名”在我们Android中一定要是唯一的,否则系统怎么能知道该找哪一个Provider呢?所以一般情况下,建议采用完整的包名加类名来标识这个ContentProvider的authority。
      • /User/21——路径,用来标识我们要操作的数据。/user/21表示的意思是——找到User中id为21的记录。其实这个相当于/AAA/123。

        综上所述,content://LiB.cprovider.myprovider.Users/User/21所代表的URI的意思为:标识LiB.cprovider.myprovider中Users表中_ID为21的User项。

        通过上面的介绍,我想大家都知道URI到底是如何标识我们的ContentProvider了,我们就来看看Android系统中为我们提供了些有关操作URI的方法吧。

      • ContentUris类——操作URI  

    withAppendedId(builder, id)——在builder最后加上id组成URI。

    Uri uri = ContentUris.withAppendedId(User.CONTENT_URI, id);

          parseId(uri)——用于从URI中提取出ID值。

    long returnID = ContentUris.parseId(User.CONTENT_URI);
      • UriMatcher类——匹配URI

        addURI(authority, path, code)——为UriMatcher添加规则,并在匹配成功后返回code值,否则返回构造函数中传入的默认值,一般为UriMatcher.NO_MATCH

        参数解释:authority——主机名,path——路径,code——匹配后返回的值

    uriMatcher.addURI(Users.AUTHORITY, "User", USER);

      4、  ContentProvider中公开的几个方法

      • public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android系统运行后,ContentProvider只有在被第一次使用它时才会被创建。
      • public Uri insert(Uri uri, ContentValues values):外部应用程序通过这个方法向 ContentProvider添加数据。
        • uri——标识操作数据的URI
        • values——需要添加数据的键值对
      • public int delete(Uri uri, String selection, String[] selectionArgs):外部应用程序通过这个方法从 ContentProvider中删除数据。
        • uri——标识操作数据的URI
        • selection——构成筛选添加的语句,如"id=1" 或者 "id=?"
        • selectionArgs——对应selection的两种情况可以传入null 或者 new String[]{"1"}
      • public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):外部应用程序通过这个方法对 ContentProvider中的数据进行更新。
        • values——对应需要更新的键值对,键为对应共享数据中的字段,值为对应的修改值
        • 其余参数同delete方法
      • public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):外部应用程序通过这个方法从ContentProvider中获取数据,并返回一个Cursor对象。
        • projection——需要从Contentprovider中选择的字段,如果为空,则返回的Cursor将包含所有的字段。
        • sortOrder——默认的排序规则
        • 其余参数同delete方法    
      • public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。
        • 如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到所有user记录的Uri为content:// LiB.cprovider.myprovider.Users /User,那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/user"。
        • 如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为21的user记录,Uri为content:// LiB.cprovider.myprovider.Users /User/21,那么返回的MIME类型字符串为:"vnd.android.cursor.item/user"。

      5、  如何公开我自己的数据?

        看了那么多,如何才能够把我们自己的数据公开出来给别的程序使用呢?

        首先,继承ContentProvider并重写它的几个抽象方法

    View Code
      1  package LiB.cprovider;
      2  
      3  import java.util.HashMap;
      4  
      5  import LiB.cprovider.Users.User;
      6  import android.content.ContentProvider;
      7  import android.content.ContentUris;
      8  import android.content.ContentValues;
      9  import android.content.UriMatcher;
     10  import android.database.Cursor;
     11  import android.database.sqlite.SQLiteDatabase;
     12  import android.database.sqlite.SQLiteQueryBuilder;
     13  import android.net.Uri;
     14  import android.text.TextUtils;
     15  
     16  public class myprovider extends ContentProvider {
     17  
     18      private DBHelper dbHelper;
     19      private static final UriMatcher uriMatcher;
     20      private static final int USER = 1;
     21      private static final int USER_ID = 2;
     22      private static HashMap<String, String> maps;
     23      static {
     24          // 当没有匹配成功是时,返回NO_MATCH的值
     25          uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
     26          // 匹配Users表中的所有User,匹配成功后返回USER整数值
     27  // content://LiB.cprovider.myprovider.Users/User
     28          uriMatcher.addURI(Users.AUTHORITY, "User", USER);
     29          // 匹配Users表中指定ID的User项,匹配成功后返回USER_ID整数值
     30  // content://LiB.cprovider.myprovider.Users/User/21
     31          uriMatcher.addURI(Users.AUTHORITY, "User/#", USER_ID);
     32  
     33          maps = new HashMap<String, String>();
     34          maps.put(User._ID, User._ID);
     35          maps.put(User.NAME, User.NAME);
     36          maps.put(User.SEX, User.SEX);
     37          maps.put(User.AGE, User.AGE);
     38      }
     39  
     40      @Override
     41      public int delete(Uri uri, String selection, String[] selectionArgs) {
     42          SQLiteDatabase db = dbHelper.getWritableDatabase();
     43          int count = 0;
     44          switch (uriMatcher.match(uri)) {
     45          case USER:
     46              count = db.delete(DBHelper.DATATABLE_NAME, selection, selectionArgs);
     47              break;
     48          case USER_ID:
     49              String noteId = uri.getPathSegments().get(1);
     50              count = db.delete(DBHelper.DATATABLE_NAME, User._ID
     51                      + "="
     52                      + noteId
     53                      + (!TextUtils.isEmpty(selection) ? " AND (" + selection
     54                              + ')' : ""), selectionArgs);
     55              break;
     56          default:
     57              throw new IllegalArgumentException();
     58          }
     59          this.getContext().getContentResolver().notifyChange(uri, null);
     60          return count;
     61      }
     62      
     63      @Override
     64      public String getType(Uri uri) {
     65          return null;
     66      }
     67  
     68      @Override
     69      public Uri insert(Uri uri, ContentValues values) {
     70          SQLiteDatabase db = dbHelper.getWritableDatabase();
     71          // User.NAME不能为空
     72          long _id = db.insert(DBHelper.DATATABLE_NAME, User.NAME, values);
     73          if (_id > 0) {
     74              Uri uri1 = ContentUris.withAppendedId(User.CONTENT_URI, _id);
     75              this.getContext().getContentResolver().notifyChange(uri1, null);
     76              return uri1;
     77          }
     78          return null;
     79      }
     80  
     81      @Override
     82      public boolean onCreate() {
     83          dbHelper = new DBHelper(this.getContext());
     84          return true;
     85      }
     86  
     87      @Override
     88      public Cursor query(Uri uri, String[] projection, String selection,
     89              String[] selectionArgs, String sortOrder) {
     90          SQLiteQueryBuilder sqb = new SQLiteQueryBuilder();
     91          switch (uriMatcher.match(uri)) {
     92          case USER:
     93              sqb.setTables(DBHelper.DATATABLE_NAME);
     94              sqb.setProjectionMap(maps);
     95              break;
     96          case USER_ID:
     97              sqb.setTables(DBHelper.DATATABLE_NAME);
     98              sqb.setProjectionMap(maps);
     99              sqb.appendWhere(User._ID + "=" + uri.getPathSegments().get(1));
    100              break;
    101          default:
    102              throw new IllegalArgumentException();
    103          }
    104          SQLiteDatabase db = dbHelper.getReadableDatabase();
    105          Cursor cursor = sqb.query(db, projection, selection, selectionArgs,
    106                  null, null, null);
    107          cursor.setNotificationUri(getContext().getContentResolver(), uri);
    108          return cursor;
    109      }
    110  
    111      @Override
    112      public int update(Uri uri, ContentValues values, String selection,
    113              String[] selectionArgs) {
    114          SQLiteDatabase db = dbHelper.getWritableDatabase();
    115          int count;
    116          switch (uriMatcher.match(uri)) {
    117          case USER:
    118              count = db.update(DBHelper.DATATABLE_NAME, values, selection,
    119                      selectionArgs);
    120              break;
    121          case USER_ID:
    122              String noteId = uri.getPathSegments().get(1);
    123              count = db.update(DBHelper.DATATABLE_NAME, values, User._ID
    124                      + "="
    125                      + noteId
    126                      + (!TextUtils.isEmpty(selection) ? " AND (" + selection+ ')' : ""), selectionArgs);
    127              break;
    128          default:
    129              throw new IllegalArgumentException();
    130          }
    131          getContext().getContentResolver().notifyChange(uri, null);
    132          return count;
    133      }
    134  }

        然后,定义我们自己的数据存储(记住,在我们公开的数据中,一定要有个_ID字段,因为在Android中,数据的存储方式是以一个表格的形式存储的,_ID字段唯一标示了每项数据,所以常规做法是将我们的类继承自BaseColumns类,关于这个类请查看官方帮助文档)

    View Code
     1  package LiB.cprovider;
     2  
     3  import android.net.Uri;
     4  import android.provider.BaseColumns;
     5  //在BaseColumns中就已经包含了我们所必须的_ID字段,具体的可以查看帮助文档
     6  //下面的类组成了一个含有User项的Users表,每一项就是一个User对象,每个对象含有name,sex,age等属性
     7  public final class Users 
     8  {
     9      //请务必记住,这个AUTHORITY一定要和你在配置文件中配置的一样
    10      public static final String AUTHORITY="LiB.cprovider.myprovider.Users";
    11      private Users(){}
    12      //包含的项
    13      public static final class User implements BaseColumns{
    14      private User(){}
    15      //标识URI
    16      public static final Uri CONTENT_URI=Uri.parse("content://"+AUTHORITY+"/User");
    17      //类型
    18      public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.LiB.Users";
    19      public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.LiB.Users";   
    20      // 表字段常量
    21      public static final String NAME = "name";    // 姓名
    22      public static final String SEX= "sex"; // 性别
    23      public static final String AGE = "age";     //年龄
    24  }
    25  }

       然后在AndroidManifest.xml中对我们的Provider进行注册

    View Code
     1 <?xml version="1.0" encoding="utf-8"?>
     2  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3      package="LiB.cprovider" android:versionCode="1" android:versionName="1.0">
     4      <uses-sdk android:minSdkVersion="9" />
     5  
     6      <application android:icon="@drawable/icon" android:label="@string/app_name">
     7          <activity android:name=".Android_ContentProviderDemoActivity"
     8              android:label="@string/app_name">
     9              <intent-filter>
    10                  <action android:name="android.intent.action.MAIN" />
    11                  <category android:name="android.intent.category.LAUNCHER" />
    12              </intent-filter>
    13          </activity>
    14          <provider 
    15  android:name=".myprovider" 
    16          android:authorities="LiB.cprovider.myprovider.Users">
    17          </provider>
    18      </application>
    19  </manifest>

         在AndroidManifest.xml文件中,配置provider节时一定要注意android:name为你的继承自ContentProvider的那个类的类名,android:authorities与你在定义自己的数据存储时所定义的AUTHORITIES字段一定要相等,虽然这个字段值可以随意,但是非常强烈的建议你采用包名加类名的方式类命名。

      6、  怎么操作我自己的数据呢?

        为了方便我们操作ContentProvider,Android系统为我们提供了ContentResolver类。我们可以使用getContentResolver()方法返回一个ContentResolver对象,并使用它与ContentProvider对应的方法来进行操作。

    View Code
     1     // 删除方法
     2      private void delete(int id) {
     3          Uri uri = ContentUris.withAppendedId(User.CONTENT_URI, id);
     4          // 使用getContentResolver()获取ContentResolver对象,并使用它的delete()方法进行数据删除操作
     5          getContentResolver().delete(uri, null, null);
     6          System.out.println("del");
     7      }
     8  
     9      // 更新
    10      private void update(int id) {
    11          Uri uri = ContentUris.withAppendedId(User.CONTENT_URI, id);
    12          ContentValues values = new ContentValues();
    13          values.put(User.NAME, "LiB");
    14          values.put(User.SEX, "male");
    15          values.put(User.AGE, 20+id);
    16          // 使用getContentResolver()获取ContentResolver对象,并使用它的update()方法进行数据更新操作
    17          getContentResolver().update(uri, values, null, null);
    18          System.out.println("update...");
    19      }
    20  
    21      // 查询
    22      private void query() {
    23          // 需要查询的列名
    24          String[] PROJECTION = new String[] { 
    25                  User._ID,
    26                  User.NAME, 
    27                  User.SEX, 
    28                  User.AGE 
    29          };
    30          // 此处也可以使用Cursor c = managedQuery(User.CONTENT_URI, PROJECTION, null,
    31  // null, null);方法来进行查询操作
    32          Cursor c = getContentResolver().query(User.CONTENT_URI, PROJECTION,
    33                  null, null, null);
    34          if (c.moveToFirst()) {
    35              for (int i = 0; i < c.getCount(); i++) {
    36                  c.moveToPosition(i);
    37                  String name = c.getString(1);
    38                  String sex = c.getString(2);
    39                  int age = c.getInt(3);
    40                  // 输出日志
    41                  Log.i("query", name + ":" + sex + ":" + age);
    42              }
    43          }
    44          System.out.println("query...");
    45      }
    46  
    47      // 插入
    48      private void insert(int id) {
    49          Uri uri = User.CONTENT_URI;
    50          ContentValues values = new ContentValues();
    51          values.put(User.NAME, "ZMR_"+id);
    52          values.put(User.SEX, "female");
    53          values.put(User.AGE, 20+id);
    54          // 使用getContentResolver()获取ContentResolver对象,并使用它的insert()方法进行数据插入操作
    55          getContentResolver().insert(uri, values);
    56          System.out.println("insert");
    57      }

    三、总结

      其实在Android中,系统已经为我们提供了许多的ContentProvider了,我们通常情况下是不需要去自定义ContentProvider的。但是,为了更好的理解ContentProvider,自己来实现一个ContentProvider是非常必要的。同时,在Android中,数据的存储方式有很多种,在上面的例子中提到了有SQLite和XML方式,下一篇笔记将介绍如何操作XML文件。

  • 相关阅读:
    为甚么 国企做互联网总做不起来?
    WEB开发:Java与Php对比
    String中的CompareTo
    String API
    死锁(Deadlock)
    100人100盏灯(详解)
    debian、ubuntu安装metasploit通用方法
    xman随机数相关题目
    CTF辅助脚本
    2019全国大学生信息安全竞赛ciscn-writeup(4web)
  • 原文地址:https://www.cnblogs.com/wyqfighting/p/3009681.html
Copyright © 2020-2023  润新知