自定义ContentProvider以及ContentObserver的使用完整详细示例

来源:互联网 发布:java包装简历 编辑:程序博客网 时间:2024/05/16 14:26

示例说明:

该示例中一共包含两个工程。其中一个工程完成了自定义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/"开头 */@Overridepublic 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());}}@Overridepublic boolean onCreate() {mSQLiteDatabaseOpenHelper=new SQLiteDatabaseOpenHelper(getContext());return true;}/** * 插入操作: * 插入操作只有一种可能:向一张表中插入 * 返回结果为新增记录对应的Uri * 方法db.insert()返回结果为新增记录对应的主键值 */@Overridepublic 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());}}/** * 更新操作: * 更新操作有两种可能:更新一张表或者更新某条数据 * 在更新某条数据时原理类似于查询某条数据,见下. */@Overridepublic 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;}/** * 删除操作: * 删除操作有两种可能:删除一张表或者删除某条数据 * 在删除某条数据时原理类似于查询某条数据,见下. */@Overridepublic 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查询条件. *  * 详细代码见下. */@Overridepublic 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);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("create table person(personid integer primary key autoincrement,name varchar(20),phone varchar(12),salary  Integer(12))");}//当数据库版本号发生变化时调用该方法@Overridepublic 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如下:
package cn.testcontentprovider;import android.app.Activity;import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected 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;@Overrideprotected 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);}@Overrideprotected void onDestroy() {super.onDestroy();if (mContentObserverSubClass!=null) {this.getContentResolver().unregisterContentObserver(mContentObserverSubClass);}}// 自定义一个内容观察者ContentObserverprivate class ContentObserverSubClass extends ContentObserver {public ContentObserverSubClass(Handler handler) {super(handler);}//采用时间戳避免多次调用onChange( )@Overridepublic 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("时间间隔过短,忽略此次更新");}}@Overridepublic boolean deliverSelfNotifications() {    return true;}}private class ClickListenerImpl implements OnClickListener {@Overridepublic 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;}@Overridepublic 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>


0 0
原创粉丝点击