虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > Android编程 > Android 中自定义ContentProvider与ContentObserver的使用简单实例

Android 中自定义ContentProvider与ContentObserver的使用简单实例
类别:Android编程   作者:码皇   来源:互联网   点击:

这篇文章主要介绍了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 copypackage 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与ContentO