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

来源:互联网 发布:无网络聊天软件 编辑:程序博客网 时间:2024/05/17 04:48

示例说明:

该示例中一共包含两个工程。其中一个工程完成了自定义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如下:

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 android:versioncode="1" android:versionname="1.0" package="cn.testcontentprovider" xmlns:android="http://schemas.android.com/apk/res/android">     <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">                               <intent-filter>                                  <category android:name="android.intent.category.LAUNCHER">            </category></action></intent-filter>        </activity>                  <provider android:authorities="cn.bs.testcontentprovider" android:exported="true" android:name="cn.testcontentprovider.ContentProviderTest">    </provider></application> </uses-permission></uses-permission></uses-permission></uses-permission></uses-sdk></manifest>


main.xml如下:

<relativelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"><button android:layout_centerinparent="true" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="该应用包含一个自定义的ContentProvider" android:textsize="15sp"></button></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 + ];    }               }


 


0 0
原创粉丝点击