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

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

程序员文章站 2023-12-18 22:30:22
android 中自定义contentprovider与contentobserver的使用简单实例 示例说明: 该示例中一共包含两个工程。其中一个工程完成了自定义...

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> 

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

上一篇:

下一篇: