温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何在Android中自定义ContentProvider与ContentObserver

发布时间:2021-06-26 17:17:36 来源:亿速云 阅读:234 作者:Leah 栏目:移动开发

今天就跟大家聊聊有关如何在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>

看完上述内容,你们对如何在Android中自定义ContentProvider与ContentObserver有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI