欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android ContentProvider

程序员文章站 2024-02-14 15:10:04
...

一.ContentProvider 使用场景:

1.ContentProvider为存储和读取数据提供了统一的接口

  1. 使用ContentProvider,应用程序可以实现数据共享

3.android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)

所以ContentProvider很适合跨进程通信,另外ContentProvider的底层是采用 Android中的Binder机制(因此Binder机制很重要)。

发现问题:

此外但是在写ContentProvider的时候,用的它跨进程通信。举个例子:A应用通过ContentProvider暴露有个接口,使B应用可以访问,此时我就考虑到一个问题,如果A应用被系统杀掉,那么B应用还可不可以获取到A应用暴露的数据,那么OK,我们带着问题去写这个ContentProvider。

二.ContentResolver

在ContentProvider的使用过程中,需要借用ContentResolver来控制ContentProvider所暴露处理的接口,作为代理来间接操作ContentProvider以获取数据。
在 Context.java 的源码中如下抽象方法

public abstract ContentResolver getContentResolver();

所以可以在所有继承Context的类中通过 getContentResovler() 方法获取ContentProvider

  ContentResolver contentResolver = getContentResovler();

三.写一个A应用MyContentProvider

1.首先在Manifest文件中注册provider,并且定义provider的uri和name

         <provider android:name="MyProvider"
                   android:authorities="cn.test.myprovider"
                   android:exported="true"
                />

2.自定义一个MyContentProvider需要继承ContentProvider并重写其中的方法。

public class MyProvider extends ContentProvider {

      private Context mContext;
      DBHelper mDbHelper = null;
      SQLiteDatabase db = null;
      public static final String AUTOHORITY = "cn.scu.myprovider";
      // 设置ContentProvider的唯一标识

      public static final int User_Code = 1;
      public static final int Job_Code = 2;

     // UriMatcher类使用:在ContentProvider 中注册URI
     private static final UriMatcher mMatcher;
       static{
            mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            // 初始化
           mMatcher.addURI(AUTOHORITY,"user", User_Code);
           mMatcher.addURI(AUTOHORITY, "job", Job_Code);
          // 若URI资源路径 = content://cn.scu.myprovider/user ,则返回***User_Code
          // 若URI资源路径 = content://cn.scu.myprovider/job ,则返回***Job_Code
  }

  // 以下是ContentProvider的6个方法

   /**
    * 初始化ContentProvider
    */
  @Override
   public boolean onCreate() {

         mContext = getContext();
         // 在ContentProvider创建时对数据库进行初始化
         // 运行在主线程,故不能做耗时操作,此处仅作展示
         mDbHelper = new DBHelper(getContext());
         db = mDbHelper.getWritableDatabase();

         // 初始化两个表的数据(先清空两个表,再各加入一个记录)
         //db.execSQL("delete from user");
        //db.execSQL("insert into user values('null','Carson');");
        //db.execSQL("insert into user values('null','Kobe');");
        //db.execSQL("insert into user values(5,'zenmeban');");

        db.execSQL("delete from job");
        db.execSQL("insert into job values(1,'Android');");
        db.execSQL("insert into job values(2,'iOS');");

        return true;
  }

   /**
     * 添加数据
     */

   @Override
   public Uri insert(Uri uri, ContentValues values) {

        // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
        // 该方法在最下面
        String table = getTableName(uri);
        ContentValues contentValues = new ContentValues();
       //contentValues.put("_id","4");
       //contentValues.put("name","buzhidao");
       // db.execSQL("insert into user values(null,'buzhidao');");
       // 向该表添加数据
        db.insert(table, null, contentValues);

       // 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
       mContext.getContentResolver().notifyChange(uri, null);

       // 通过ContentUris类从URL中获取ID
      //long personid = ContentUris.parseId(uri);
      //System.out.println(personid);
       Log.i("wangrui",""+contentValues);
       return uri;
    }

   /**
     * 查询数据
     */
   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder) {
        // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
       // 该方法在最下面
      String table = getTableName(uri);

      // 通过ContentUris类从URL中获取ID
      //long personid = ContentUris.parseId(uri);
      //System.out.println(personid);

    // 查询数据
    return db.query(table,projection,selection,selectionArgs,null,null,sortOrder,null);
  }

  /**
   * 更新数据
   */
  @Override
  public int update(Uri uri, ContentValues values, String selection,
                  String[] selectionArgs) {

      String table = getTableName(uri);
      int count = db.update(table,values,selection,selectionArgs);
      if(count>0) {
          mContext.getContentResolver().notifyChange(uri, null);
      }
      return 0;
  }

   /**
    * 删除数据
    */
   @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
          // 由于不展示,此处不作展开
         String table = getTableName(uri);

          return 0;
  }

   @Override
    public String getType(Uri uri) {

       // 由于不展示,此处不作展开
       return null;
   }

   /**
     * 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
     */
    private String getTableName(Uri uri){
        String tableName = null;
        switch (mMatcher.match(uri)) {
            case User_Code:
                  tableName = DBHelper.USER_TABLE_NAME;
                  break;
           case Job_Code:
                 tableName = DBHelper.JOB_TABLE_NAME;
                 break;
         }
         return tableName;
     }
}

3.创建数据库DBHelper

public class DBHelper extends SQLiteOpenHelper {

      // 数据库名
      private static final String DATABASE_NAME = "finch.db";

       // 表名
      public static final String USER_TABLE_NAME = "user";
      public static final String JOB_TABLE_NAME = "job";

      private static final int DATABASE_VERSION = 1;
      //数据库版本号

   public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
   }

     @Override
      public void onCreate(SQLiteDatabase db) {

    // 创建两个表格:用户表 和职业表
         db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)");

         db.execSQL("CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " job TEXT)");
}

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

    }
}

四 .写一个查找这个provider的另一个demo,B应用

这个demo中只是用来查找前一个应用提供的 contentProvider,只贴出关键代码

       cursor = getContentResolver().query(uri_user, null, null, null, null);
           if (cursor != null) {
              while (cursor.moveToNext()) {
              // int displayName = cursor.getInt(0);
              // String number = cursor.getString(1);
              // String time = cursor.getString(2);
             // 获取联系人姓名
              String displayName = cursor.getString(cursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
             //获取联系人姓名
             String number = cursor.getString(cursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.Phone.NUMBER));

              contactsList.add(displayName + "\n" + number + " ..");
          }
        cursor.close();
    }

ok,两个demo到这里就写完了,最后结果说明,从B应用中可以成功获取到A应用的提供的contentProvider,此时如果把A应用从后台杀掉也是可以成功获取到数据。后续会将两个应用的demo上传GitHub。