当前位置: 移动技术网 > IT编程>移动开发>Android > Android 中自定义ContentProvider与ContentObserver的使用简单实例

Android 中自定义ContentProvider与ContentObserver的使用简单实例

2019年07月24日  | 移动技术网IT编程  | 我要评论

海安县紫石中学,非诚勿扰200期,东明家具城

android 中自定义contentprovider与contentobserver的使用简单实例

示例说明:

该示例中一共包含两个工程。其中一个工程完成了自定义contentprovider,另外一个工程用于测试该自定义contentprovider且在该工程中使用了contentobserver监听自定义contentprovider的数据变化

以下代码为工程testcontentprovider

contentprovidertest如下:

package cn.testcontentprovider; 
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; 
/** 
 * demo描述: 
 * 自定义contentprovider的实现 
 * contentprovider主要用于在不同的应用程序之间共享数据,这也是官方推荐的方式. 
 * 
 * 注意事项: 
 * 1 在androidmanifest.xml中注册contentprovider时的属性 
 *  android:exported="true"表示允许其他应用访问. 
 * 2 注意*和#这两个符号在uri中的作用 
 *  其中*表示匹配任意长度的字符 
 *  其中#表示匹配任意长度的数据 
 *  所以: 
 *  一个能匹配所有表的uri可以写成: 
 *  content://cn.bs.testcontentprovider/* 
 *  一个能匹配person表中任意一行的uri可以写成: 
 *  content://cn.bs.testcontentprovider/person/# 
 *  
 */ 
public class contentprovidertest extends contentprovider { 
  private sqlitedatabaseopenhelper msqlitedatabaseopenhelper; 
  private final static string authority="cn.bs.testcontentprovider"; 
  private static urimatcher murimatcher; 
  private static final int person_dir = 0; 
  private static final int person = 1; 
   
  /** 
   * 利用静态代码块初始化urimatcher 
   * 在urimatcher中包含了多个uri,每个uri代表一种操作 
   * 当调用urimatcher.match(uri uri)方法时就会返回该uri对应的code; 
   * 比如此处的persons和person 
   */ 
  static { 
    murimatcher = new urimatcher(urimatcher.no_match); 
    // 该uri表示返回所有的person,其中persons为该特定uri的标识码 
    murimatcher.adduri(authority, "person", person_dir); 
    // 该uri表示返回某一个person,其中person为该特定uri的标识码 
    murimatcher.adduri(authority, "person/#", person); 
  } 
   
   
  /** 
   * 在自定义contentprovider中必须覆写gettype(uri uri)方法. 
   * 该方法用于获取uri对象所对应的mime类型. 
   * 
   * 一个uri对应的mime字符串遵守以下三点: 
   * 1 必须以vnd开头 
   * 2 如果该uri对应的数据可能包含多条记录,那么返回字符串应该以"vnd.android.cursor.dir/"开头 
   * 3 如果该uri对应的数据只包含一条记录,那么返回字符串应该以"vnd.android.cursor.item/"开头 
   */ 
  @override 
  public string gettype(uri uri) { 
    switch (murimatcher.match(uri)) { 
    case person_dir: 
      return "vnd.android.cursor.dir/"+authority+".persons"; 
    case person: 
      return "vnd.android.cursor.item/"+authority+".person"; 
    default: 
      throw new illegalargumentexception("unknown uri"+uri.tostring()); 
    } 
  }   
 
   
  @override 
  public boolean oncreate() { 
    msqlitedatabaseopenhelper=new sqlitedatabaseopenhelper(getcontext()); 
    return true; 
  } 
   
 
  /** 
   * 插入操作: 
   * 插入操作只有一种可能:向一张表中插入 
   * 返回结果为新增记录对应的uri 
   * 方法db.insert()返回结果为新增记录对应的主键值 
   */ 
  @override 
  public uri insert(uri uri, contentvalues values) { 
    sqlitedatabase db = msqlitedatabaseopenhelper.getwritabledatabase(); 
    switch (murimatcher.match(uri)) { 
    case person_dir: 
      long newid = db.insert("person", "name,phone,salary", values); 
      //向外界通知该contentprovider里的数据发生了变化 ,以便contentobserver作出相应  
      getcontext().getcontentresolver().notifychange(uri, null);  
      return contenturis.withappendedid(uri, newid); 
    default: 
      throw new illegalargumentexception("unknown uri" + uri.tostring()); 
    } 
  } 
   
  /** 
   * 更新操作: 
   * 更新操作有两种可能:更新一张表或者更新某条数据 
   * 在更新某条数据时原理类似于查询某条数据,见下. 
   */ 
  @override 
  public int update(uri uri, contentvalues values, string selection,string[] selectionargs) { 
    sqlitedatabase db = msqlitedatabaseopenhelper.getwritabledatabase(); 
    int updatednum = 0; 
    switch (murimatcher.match(uri)) { 
    // 更新表 
    case person_dir: 
      updatednum = db.update("person", values, selection, selectionargs); 
      break; 
    // 按照id更新某条数据 
    case person: 
      long id = contenturis.parseid(uri); 
      string where = "personid=" + id; 
      if (selection != null && !"".equals(selection.trim())) { 
        where = selection + " and " + where; 
      } 
      updatednum = db.update("person", values, where, selectionargs); 
      break; 
    default: 
      throw new illegalargumentexception("unknown uri" + uri.tostring()); 
    } 
    //向外界通知该contentprovider里的数据发生了变化 ,以便contentobserver作出相应  
    getcontext().getcontentresolver().notifychange(uri, null);  
    return updatednum; 
  } 
   
  /** 
   * 删除操作: 
   * 删除操作有两种可能:删除一张表或者删除某条数据 
   * 在删除某条数据时原理类似于查询某条数据,见下. 
   */ 
  @override 
  public int delete(uri uri, string selection, string[] selectionargs) { 
    sqlitedatabase db = msqlitedatabaseopenhelper.getwritabledatabase(); 
    int deletednum = 0; 
    switch (murimatcher.match(uri)) { 
    // 删除表 
    case person_dir: 
      deletednum = db.delete("person", selection, selectionargs); 
      break; 
    // 按照id删除某条数据 
    case person: 
      long id = contenturis.parseid(uri); 
      string where = "personid=" + id; 
      if (selection != null && !"".equals(selection.trim())) { 
        where = selection + " and " + where; 
      } 
      deletednum = db.delete("person", where, selectionargs); 
      break; 
    default: 
      throw new illegalargumentexception("unknown uri" + uri.tostring()); 
    } 
    //向外界通知该contentprovider里的数据发生了变化 ,以便contentobserver作出相应  
    getcontext().getcontentresolver().notifychange(uri, null);  
    return deletednum; 
  } 
 
  /** 
   * 查询操作: 
   * 查询操作有两种可能:查询一张表或者查询某条数据 
   * 
   * 注意事项: 
   * 在查询某条数据时要注意--因为此处是按照personid来查询 
   * 某条数据,但是同时可能还有其他限制.例如: 
   * 要求personid为2且name为xiaoming1 
   * 所以在查询时分为两步: 
   * 第一步: 
   * 解析出personid放入where查询条件 
   * 第二步: 
   * 判断是否有其他限制(如name),若有则将其组拼到where查询条件. 
   * 
   * 详细代码见下. 
   */ 
  @override 
  public cursor query(uri uri, string[] projection, string selection,string[] selectionargs, string sortorder) { 
    sqlitedatabase db = msqlitedatabaseopenhelper.getwritabledatabase(); 
    cursor cursor =null; 
    switch (murimatcher.match(uri)) { 
    // 查询表 
    case person_dir: 
      cursor = db.query("person", projection, selection, selectionargs,null, null, sortorder); 
      break; 
    // 按照id查询某条数据 
    case person: 
      // 第一步: 
      long id = contenturis.parseid(uri); 
      string where = "personid=" + id; 
      // 第二步: 
      if (selection != null && !"".equals(selection.trim())) { 
        where = selection + " and " + where; 
      } 
      cursor = db.query("person", projection, where, selectionargs, null, null, sortorder); 
      break; 
    default: 
      throw new illegalargumentexception("unknown uri" + uri.tostring()); 
    } 
    return cursor; 
  } 
   
 
} 

sqlitedatabaseopenhelper如下:

package cn.testcontentprovider; 
import android.content.context; 
import android.database.sqlite.sqlitedatabase; 
import android.database.sqlite.sqliteopenhelper; 
public class sqlitedatabaseopenhelper extends sqliteopenhelper { 
  public sqlitedatabaseopenhelper(context context) { 
    super(context, "contentprovidertest.db", null, 1); 
  } 
 
  @override 
  public void oncreate(sqlitedatabase db) { 
    db.execsql("create table person(personid integer primary key autoincrement,name varchar(20),phone varchar(12),salary integer(12))");     
  } 
 
  //当数据库版本号发生变化时调用该方法 
  @override 
  public void onupgrade(sqlitedatabase db, int arg1, int arg2) { 
    //db.execsql("alter table person add phone varchar(12) null"); 
    //db.execsql("alter table person add salary integer null"); 
  } 
 
} 

mainactivity如下:
[java] view plain copy
package cn.testcontentprovider; 
import android.app.activity; 
import android.os.bundle; 
public class mainactivity extends activity { 
  @override 
  protected void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.main); 
  } 
 
} 

androidmanifest.xml如下:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  package="cn.testcontentprovider" 
  android:versioncode="1" 
  android:versionname="1.0" > 
 
  <uses-sdk 
    android:minsdkversion="8" 
    android:targetsdkversion="8" /> 
 
  <uses-permission android:name="android.permission.internet" /> 
  <uses-permission android:name="android.permission.access_network_state" /> 
  <uses-permission android:name="android.permission.write_external_storage" /> 
  <uses-permission android:name="android.permission.mount_unmount_filesystems" /> 
   
  <application 
    android:allowbackup="true" 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/apptheme" > 
    <activity 
      android:name="cn.testcontentprovider.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="cn.testcontentprovider.contentprovidertest" 
      android:authorities="cn.bs.testcontentprovider" 
      android:exported="true" 
     /> 
  </application> 
 
</manifest> 

main.xml如下:

<relativelayout  
  xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  > 
 
   <button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="该应用包含一个自定义的contentprovider" 
    android:textsize="15sp" 
   android:layout_centerinparent="true" 
  /> 
 
</relativelayout> 



以下代码为工程testbaidu

mainactivity如下:

package cn.testbaidu; 
import android.net.uri; 
import android.os.bundle; 
import android.os.handler; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.widget.button; 
import android.app.activity; 
import android.content.contentresolver; 
import android.content.contentvalues; 
import android.database.contentobserver; 
import android.database.cursor; 
/** 
 * demo描述: 
 * 应用a(testbaidu)调用另外一个应用(testcontentprovider)中的自定义contentprovider,即: 
 * 1 自定义contentprovider的使用 
 * 2 其它应用调用该contentprovider 
 * 3 contentobserver的使用 
 * 
 * 备注说明: 
 * 1 该例子在以前版本的基础上整理了代码 
 * 2 该例子在以前版本的基础上融合了contentobserver的使用 
 *  利用contentobserver随时监听contentprovider的数据变化. 
 *  为实现该功能需要在自定义的contentprovider的insert(),update(),delete() 
 *  方法中调用getcontext().getcontentresolver().notifychange(uri, null); 
 *  向外界通知该contentprovider里的数据发生了变化 ,以便contentobserver作出相应  
 * 
 * 测试方法: 
 * 1 依次测试contentprovider的增查删改(注意该顺序)!! 
 * 2 其它应用查询该contentprovider的数据 
 * 
 */ 
public class mainactivity extends activity { 
  private button maddbutton; 
  private button mdeletebutton; 
  private button mupdatebutton; 
  private button mquerybutton; 
  private button mtypebutton; 
  private long lasttime=0; 
  private contentresolver mcontentresolver; 
  private contentobserversubclass mcontentobserversubclass; 
  @override 
  protected void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.main); 
    init(); 
    initcontentobserver(); 
  } 
 
  private void init() { 
    mcontentresolver=this.getcontentresolver(); 
     
    maddbutton=(button) findviewbyid(r.id.addbutton); 
    maddbutton.setonclicklistener(new clicklistenerimpl()); 
     
    mdeletebutton=(button) findviewbyid(r.id.deletebutton); 
    mdeletebutton.setonclicklistener(new clicklistenerimpl()); 
     
    mupdatebutton=(button) findviewbyid(r.id.updatebutton); 
    mupdatebutton.setonclicklistener(new clicklistenerimpl()); 
     
    mquerybutton=(button) findviewbyid(r.id.querybutton); 
    mquerybutton.setonclicklistener(new clicklistenerimpl()); 
     
    mtypebutton=(button) findviewbyid(r.id.typebutton); 
    mtypebutton.setonclicklistener(new clicklistenerimpl()); 
     
  } 
   
   
 
  // 注册一个针对contentprovider的contentobserver用来观察内容提供者的数据变化 
  private void initcontentobserver() { 
    uri uri = uri.parse("content://cn.bs.testcontentprovider/person"); 
    mcontentobserversubclass=new contentobserversubclass(new handler()); 
    this.getcontentresolver().registercontentobserver(uri, true,mcontentobserversubclass); 
  } 
   
  @override 
  protected void ondestroy() { 
    super.ondestroy(); 
    if (mcontentobserversubclass!=null) { 
      this.getcontentresolver().unregistercontentobserver(mcontentobserversubclass); 
    } 
  } 
 
   
   
   
  // 自定义一个内容观察者contentobserver 
  private class contentobserversubclass extends contentobserver { 
 
    public contentobserversubclass(handler handler) { 
      super(handler); 
    } 
 
    //采用时间戳避免多次调用onchange( ) 
    @override 
    public void onchange(boolean selfchange) { 
      super.onchange(selfchange); 
      system.out.println("contentobserver onchange() selfchange="+ selfchange); 
      if (system.currenttimemillis()-lasttime>2000) { 
        contentresolver resolver = getcontentresolver(); 
        uri uri = uri.parse("content://cn.bs.testcontentprovider/person"); 
        // 获取最新的一条数据 
        cursor cursor = resolver.query(uri, null, null, null,"personid desc limit 1"); 
        while (cursor.movetonext()) { 
          int personid = cursor.getint(cursor.getcolumnindex("personid")); 
          system.out.println("内容提供者中的数据发生变化,现数据中第一条数据的personid="+ personid); 
        } 
        cursor.close(); 
        lasttime=system.currenttimemillis(); 
      }else{ 
        system.out.println("时间间隔过短,忽略此次更新"); 
      } 
       
       
    } 
     
    @override 
    public boolean deliverselfnotifications() { 
      return true; 
    } 
     
  } 
   
   
   
   
 
  private class clicklistenerimpl implements onclicklistener { 
    @override 
    public void onclick(view v) { 
      switch (v.getid()) { 
      case r.id.addbutton: 
        person person = null; 
        for (int i = 0; i < 5; i++) { 
          person = new person("xiaoming" + i, "9527" + i, (8888 + i)); 
          testinsert(person); 
        } 
        break; 
      case r.id.deletebutton: 
        testdelete(1); 
        break; 
      case r.id.updatebutton: 
        testupdate(3); 
        break; 
      case r.id.querybutton: 
        // 查询表 
        // queryfromcontentprovider(-1); 
 
        // 查询personid=2的数据 
        testquery(2); 
        break; 
      case r.id.typebutton: 
        testtype(); 
        break; 
      default: 
        break; 
      } 
 
    } 
 
  } 
  private void testinsert(person person) { 
    contentvalues contentvalues=new contentvalues(); 
    contentvalues.put("name", person.getname()); 
    contentvalues.put("phone", person.getphone()); 
    contentvalues.put("salary",person.getsalary()); 
    uri inserturi=uri.parse("content://cn.bs.testcontentprovider/person"); 
    uri returnuri=mcontentresolver.insert(inserturi, contentvalues); 
    system.out.println("新增数据:returnuri="+returnuri); 
  } 
   
  private void testdelete(int index){ 
    uri uri=uri.parse("content://cn.bs.testcontentprovider/person/"+string.valueof(index)); 
    mcontentresolver.delete(uri, null, null); 
  } 
   
  private void testupdate(int index){ 
    uri uri=uri.parse("content://cn.bs.testcontentprovider/person/"+string.valueof(index)); 
    contentvalues values=new contentvalues(); 
    values.put("name", "hanmeimei"); 
    values.put("phone", "1234"); 
    values.put("salary", 333); 
    mcontentresolver.update(uri, values, null, null); 
  } 
 
  private void testquery(int index) { 
    uri uri=null; 
    if (index<=0) { 
      //查询表 
      uri=uri.parse("content://cn.bs.testcontentprovider/person"); 
    } else { 
       //按照id查询某条数据 
      uri=uri.parse("content://cn.bs.testcontentprovider/person/"+string.valueof(index)); 
    } 
     
    //对应上面的:查询表 
    //cursor cursor= mcontentresolver.query(uri, null, null, null, null); 
     
    //对应上面的:查询personid=2的数据 
    //注意:因为name是varchar字段的,所以应该写作"name='xiaoming1'" 
    //   若写成"name=xiaoming1"查询时会报错 
    cursor cursor= mcontentresolver.query(uri, null, "name='xiaoming1'", null, null); 
     
    while(cursor.movetonext()){ 
      int personid=cursor.getint(cursor.getcolumnindex("personid")); 
      string name=cursor.getstring(cursor.getcolumnindex("name")); 
      string phone=cursor.getstring(cursor.getcolumnindex("phone")); 
      int salary=cursor.getint(cursor.getcolumnindex("salary")); 
      system.out.println("查询得到:personid=" + personid+",name="+name+",phone="+phone+",salary="+salary); 
    } 
    cursor.close(); 
  } 
   
  private void testtype(){ 
    uri diruri=uri.parse("content://cn.bs.testcontentprovider/person"); 
    string dirtype=mcontentresolver.gettype(diruri); 
    system.out.println("dirtype:"+dirtype); 
     
    uri itemuri=uri.parse("content://cn.bs.testcontentprovider/person/3"); 
    string itemtype=mcontentresolver.gettype(itemuri); 
    system.out.println("itemtype:"+itemtype); 
  } 
 
} 

person如下:

package cn.testbaidu; 
 
public class person { 
  private integer id; 
  private string name; 
  private string phone; 
  private integer salary; 
  public person(string name, string phone,integer salary) { 
    this.name = name; 
    this.phone = phone; 
    this.salary=salary; 
  } 
  public person(integer id, string name, string phone,integer salary) { 
    this.id = id; 
    this.name = name; 
    this.phone = phone; 
    this.salary=salary; 
  } 
  public integer getid() { 
    return id; 
  } 
  public void setid(integer id) { 
    this.id = id; 
  } 
  public string getname() { 
    return name; 
  } 
  public void setname(string name) { 
    this.name = name; 
  } 
  public string getphone() { 
    return phone; 
  } 
  public void setphone(string phone) { 
    this.phone = phone; 
  } 
  public integer getsalary() { 
    return salary; 
  } 
  public void setsalary(integer salary) { 
    this.salary = salary; 
  } 
  @override 
  public string tostring() { 
    return "person [id=" + id + ", name=" + name + ", phone=" + phone+ ", salary=" + salary + "]"; 
  } 
   
   
   
} 

main.xml如下:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" > 
 
  <button 
    android:id="@+id/addbutton" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerhorizontal="true" 
    android:layout_margintop="30dip" 
    android:text="增加" 
    android:textsize="20sp" /> 
   
   <button 
    android:id="@+id/querybutton" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerhorizontal="true" 
    android:layout_margintop="30dip" 
     android:layout_below="@id/addbutton" 
    android:text="查询" 
    android:textsize="20sp" /> 
   
 
  <button 
    android:id="@+id/deletebutton" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerhorizontal="true" 
    android:layout_margintop="30dip" 
    android:layout_below="@id/querybutton" 
    android:text="删除" 
    android:textsize="20sp" /> 
 
  <button 
    android:id="@+id/updatebutton" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerhorizontal="true" 
    android:layout_margintop="30dip" 
     android:layout_below="@id/deletebutton" 
    android:text="修改" 
    android:textsize="20sp" /> 
 
  
   <button 
    android:id="@+id/typebutton" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerhorizontal="true" 
    android:layout_margintop="30dip" 
     android:layout_below="@id/updatebutton" 
    android:text="类型" 
    android:textsize="20sp" /> 
 
</relativelayout> 

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网