四大组件之一 ContentProvider

概念

ContentProvider作为四大组件之一,他的地位不容忽视。它的作用是为不同应用程序数据共享,提供统一接口 我们其他应用程序要调用android系统中的应用,这时候就要用到ContentProvider,也可以我们利用ContentProvider编写自己的内容提供者,供其他应用使用

ContentProvider如何实现数据共享的

ContentProvider通过URI唯一标识其他要访问的数据,开发人员一般通过ContentResolver来进行操作ContentProvider,可进行增删改查实现对数据的共享。

ContentProvider讲解

ContentProvider是一个抽象类,如果要开发自己的内容提供者都要继承这个类并进行重写。主要实现以下方法:

public boolean onCreate()

在创建ContentProvider的时候进行调用

public Cursor query()

用来查询指定的URI返回一个Cursor

public Uri insert()

向指定RUI的ContentProvider中插入数据

public int update()

用户更新指定的RUI的数据

public int delete()

用户删除指定的RUI的数据

public String getType()

用于返回指定的Uri中的数据MIME类型

自定义ContentProvider讲解

我们创建一个数据库的ContentProvider类来实现数据共享,自定义名称为MyProvider

package com.haolin.contentprovider.sample;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class MyProvider extends ContentProvider {

  private Context mContext;
  DBHelper mDbHelper = null;
  SQLiteDatabase db = null;
  public static final String AUTOHORITY = "com.haolin.contentprovider.sample.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);
  }

  // 以下是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(1,'Carson');");
      db.execSQL("insert into user values(2,'Kobe');");

      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);

      // 向该表添加数据
      db.insert(table, null, values);

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

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

      return uri;
      }

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

  /**
   * 更新数据
   */
  @Override
  public int update(Uri uri, ContentValues values, String selection,
                    String[] selectionArgs) {
      // 由于不展示,此处不作展开
      return 0;
  }

  /**
   * 删除数据
   */
  @Override
  public int delete(Uri uri, String selection, String[] selectionArgs) {
      // 由于不展示,此处不作展开
      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;
      }
  }


  • ContentProvider作为四大组件之一,我们必须再AndroidManifest.xml文件中进行注册

      <provider
          android:authorities="com.haolin.contentprovider.sample.MyProvider"
          android:name=".MyProvider"
          android:exported="true"/>
          

这里的authorities唯一标识该内容提供者,这样其它的应用才可以找到该内容提供者并操作它的数据;exported为true当前内容提供者可以被其它应用使用,默认为true

操作ContentProvider里的数据

我们在MainActivity中来操作ContentProvider数据 或者新建个项目也可直接操作

  /*
       * 对user表进行操作
       */

      // 设置URI
      Uri uri_user = Uri.parse("content://com.haolin.contentprovider.sample.MyProvider/user");

      // 插入表中数据
      ContentValues values = new ContentValues();
      values.put("_id", 3);
      values.put("name", "Iverson");


      // 获取ContentResolver
      ContentResolver resolver =  getContentResolver();
      // 通过ContentResolver 根据URI 向ContentProvider中插入数据
      resolver.insert(uri_user,values);

      // 通过ContentResolver 向ContentProvider中查询数据
      Cursor cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null);
      assert cursor != null;
      while (cursor.moveToNext()){
          System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1));
          // 将表中数据全部输出
      }
      cursor.close();
      // 关闭游标

      /*
       * 对job表进行操作
       */
      // 和上述类似,只是URI需要更改,从而匹配不同的URI CODE,从而找到不同的数据资源
      Uri uri_job = Uri.parse("content://com.haolin.contentprovider.sample.MyProvider/job");

      // 插入表中数据
      ContentValues values2 = new ContentValues();
      values2.put("_id", 3);
      values2.put("job", "NBA Player");

      // 获取ContentResolver
      ContentResolver resolver2 =  getContentResolver();
      // 通过ContentResolver 根据URI 向ContentProvider中插入数据
      resolver2.insert(uri_job,values2);

      // 通过ContentResolver 向ContentProvider中查询数据
      Cursor cursor2 = resolver2.query(uri_job, new String[]{"_id","job"}, null, null, null);
      assert cursor2 != null;
      while (cursor2.moveToNext()){
          System.out.println("query job:" + cursor2.getInt(0) +" "+ cursor2.getString(1));
          // 将表中数据全部输出
      }
      cursor2.close();
      // 关闭游标
      

这样我们可以对ContentProvider进行增删改查等操作。

ContentObserver

  • 注册ContentObserver来监听对应uri的数据变化,这步不是必须的,如果不需要监听数据变化也可以不注册

  • 首先获取ContentResolver对象
    getContentResolver() 在进行注册Observer
    resolver.registerContentObserver(uri_user,true,new TestContentObs(handler));

  • 我们需要创建个类继承ContentObserver

package com.haolin.contentprovider.testcontentprovider;

import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;

/**
* 作者:haoLin_Lee on 2019/05/12 12:18
* 邮箱:Lhaolin0304@sina.com
* class:
*/
public class TestContentObs extends ContentObserver {

  Handler handler;
  public TestContentObs(Handler handler) {
      super(handler);
      this.handler = handler;
  }

  @Override
  public void onChange(boolean selfChange, Uri uri) {
      super.onChange(selfChange, uri);

      Message message = Message.obtain();
      message.obj = uri;
      handler.sendMessage(message);
  }
}

如果数据库内容有更新,ContentObserver在收到数据变化的通知后通过Handler机制来通知主线程更新UI

感谢大家的阅读

给个赞呗
有问题及时反馈,谢谢大家

关注我 GitHub

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容