ContentProvider内容提供者

来源:互联网 发布:隔声计算软件 编辑:程序博客网 时间:2024/05/01 04:44
ContentProvider内容提供者

ContentProvider 进程间通讯,进程间数据的访问/对外共享数据用

优点:提供了统一的访问方式

原理分析图

图片1.png

图片2.png


实现抽象类ContentProvider

  安卓应用实现抽象类ContentProvider,并实现对本地数据库增删查改的四个方法,且在清单文件注册该ContentProvider。就如同给其他应用提供了一个读取本地数据的接口。

public class PersonProvider extends ContentProvider {

private DBhelp dbOpenHelper;

//UriMatcher

//addURI(authority, path, code);注册Uri,指定code

//match(uri);匹配Uri,如果有返回code,无返回-1.

//UriMatcher 其实是一个arrayList集合

        private static final UriMatcher MATCHER = new UriMatcher(

                        UriMatcher.NO_MATCH);// 判断Uri

        private static final int PERSONS = 1;

        private static final int PERSON = 2;

        static {

                // (主机名,路径部分,匹配码);

                // 添加进了要等待的匹配的路径

                MATCHER.addURI("com.cym.provides.PersonProvider", "person", PERSONS);

                MATCHER.addURI("com.cym.provides.PersonProvider", "person/#", PERSON); // #

                                                                                                                                                                // 代表数字

                                                                                                                                                                // *

                                                                                                                                                                // 代表所有字符

        }

@Override

        public boolean onCreate() {// 这个方法不是由程序员调用的而是由系统调用的,当这个程序启动被创建出来后这个方法自动调用,所以它只会被调用一次,适于做数据初始化操作。

         ContentProvider在启动应用程序的时候创建。防止并发状态,当android应用程序安装的时候,会在注册表里面把应用程序所有的信息进行注册。所有在开机之后,系统里面所有的contentProvider都会被创建出来

        dbOpenHelper = new DBhelp(getContext());

                return false;

        }

        // 我们还需要判断URI 这样就能够知道外部应用操作的处理方式

        // 以下方法都是提供给外部应用操作query,insert,delete,update

//Uri  与  ContentUri

//ContentUris.parseId(uri);得到当前uri的资源id

//Uri.parse(conten://authority/path);将字符串解析成Uri对象

// ContentUris.withAppendedId(uri, id);给当前uri添加id,并且返回新的uri:

        @Override

        public Cursor query(Uri uri, String[] projection, String selection,

                        String[] selectionArgs, String sortOrder) {

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

                Cursor cursor = null;

                switch (MATCHER.match(uri)) {

                case PERSONS:

                        cursor = db.query("person", projection, selection, selectionArgs,

                                        null, null, sortOrder);

                        break;

                case PERSON:

//得到当前uri的资源id

                        long rowid = ContentUris.parseId(uri);

                        String where = "_id=" + rowid;

                        if (selection != null && !"".equals(selection.trim())) {

                                where += " and " + selection;

                        }

                        cursor = db.query("person", projection, where, selectionArgs, null,

                                        null, sortOrder);

                        break;

                default:

                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);

                }

                return cursor;

       

        }

        // 返回操作的内容文件

        @Override

        public String getType(Uri uri) {

                switch (MATCHER.match(uri)) {

                case PERSONS:

                         return "vnd.android.cursor.dir/person";

                case PERSON:

                         return "vnd.android.cursor.item/person";

                default:

                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);

                }

        }

        @Override

        public Uri insert(Uri uri, ContentValues values) {

                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

                switch (MATCHER.match(uri)) {

                case PERSONS:

                        long rowid = db.insert("person", "name", values);// 等于你的主键值

                        // content://com.cym.provides.personprovider/person/10

                        // Uri insertUri =

                        // Uri.parse("content://com.cym.provides.personprovider/person/"+rowid);

                        // 两种方法

                        Uri insertUri = ContentUris.withAppendedId(uri, rowid);

                        //通过上下文拿到contentResolver

                                Context context = getContext();

                                ContentResolver cr = context.getContentResolver();

                                //调用该方法时 通知监听

                                cr.notifyChange(uri, null);

                        return insertUri;

                default:

                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);

                }

                }

        }

        @Override

        public int delete(Uri uri, String selection, String[] selectionArgs) {

               

        }

        @Override

        public int update(Uri uri, ContentValues values, String selection,

                       

        }

}

清单文件注册

安卓应用提供给其他应用操作本地数据的接口,必须在清单文件注册。

在application标签内部添加provider标签

<providerandroid:name=".PersonProvider"android:authorities="com.cym.provides.PersonProvider"/>

Name参数表示Provider的位置。. 代表在此包底下

Authorities参数表示域名类似于www.hao123.com (必须唯一:本地唯一)

虽然没有规定Authorities的书写规范,但是我们一般使用PersonProvider的全名

例:com.cym.provides.PersonProvider

其他应用访问

为什么使用uri

保证数据的安全性不让所有的数据对外暴露,所以我们可以指定只有那些uri可以被被人访问,所以db中放入一组uri集合

其他应用通过Context.getContentResolver()得到ContentResolver对象,根据指定的Uri可以调用ContentProvider对应的增删查改方法对数据库进行操作。

客户端的ContentResolver对象要想调用服务端ContentProvider对象的响应的方法,也必须通过该ContentProvider对应的Uri找到ContentProvider,才能实现调用。

Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider 2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

图片3.png

ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://

主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:

要操作person表中id10的记录,可以构建这样的路径:/person/10

要操作person表中id10的记录的name字段, person/10/name

要操作person表中的所有记录,可以构建这样的路径:/person

要操作xxx表中的记录,可以构建这样的路径:/xxx

当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:

要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")

//生成指向ServerCPUri实例对象

//得到域名

        uri=Uri.parse("content://com.huaao.ContentProvider");

//拿到resovler

ContentResolver cr= this.getContext().getContentResolver();

        //调用ContentResolver对象的query()方法。传入域名

        cr.query(uri, null, null, null, null);

//客户端代码.

delete.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {                                //指定资源id

        uri=Uri.parse("content://com.huaao.ContentProvider/student/2");

        //调用CRdelete()方法

        cr.delete(url, null, null);

        }

});

监听数据更改

图片4.png

ContentObserver

安卓提供ContentObserver实现数据变化后监听

监听三步骤:

1,实现抽象类 ContentObserver,重写onChange()方法

2,调用ContentProvider注册ContentObserver

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        ContentResolver cr = getContentResolver();

        Uri uri = Uri.parse("content://com.cym.provides.PersonProvider/person");

        Cursor query = cr.query(uri, null, null, null, null);

        while (query.moveToNext()) {

               

            Log.i(TAG, query.getString(query.getColumnIndex("name")));

                }

        Log.i(TAG, "第一次数据查询完了");

        ContentObserver observer = new MyContentObserver(new Handler());

        //注册监听

        cr.registerContentObserver(uri, true, observer);

}

//实现抽象类 ContentObserver

   private class MyContentObserver extends ContentObserver{

                public MyContentObserver(Handler handler) {

                        super(handler);

                        // TODO Auto-generated constructor stub

                }

                @Override

//重写onchenge

                public void onChange(boolean selfChange) {

                 

                        super.onChange(selfChange);

                         ContentResolver cr = getContentResolver();

                         Uri uri = Uri.parse("content://com.cym.provides.PersonProvider/person");

                        Cursor query = cr.query(uri, null, null, null, null);

                        while (query.moveToNext()) {

                               

                            Log.i(TAG, query.getString(query.getColumnIndex("name")));

                                }

                        Log.i(TAG, "第二次次数据查询完了");

                       

                }

    }

registerContentObserver(uri,是否连带子Uri,Observer对象);

3, 当数据发生变化,提醒监听者

notifyChange(uri, Observer);

在你要监听的方法里写入notifyChange(uri, Observer);

例子:

public Uri insert(Uri uri, ContentValues values) {

                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

                switch (MATCHER.match(uri)) {

                case PERSONS:

                        long rowid = db.insert("person", "name", values);// 等于你的主键值

                        // content://com.cym.provides.personprovider/person/10

                        // Uri insertUri =

                        // Uri.parse("content://com.cym.provides.personprovider/person/"+rowid);

                        // 两种方法

                        Uri insertUri = ContentUris.withAppendedId(uri, rowid);

                        //通过上下文拿到contentResolver

                                Context context = getContext();

                                ContentResolver cr = context.getContentResolver();

                                //调用该方法时 通知监听

                                cr.notifyChange(uri, null);

                        return insertUri;

                default:

                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);

                }

        }

最后结果流程就是  第一个次查询数据完成之后,我们在给查询这个应用注册了监听并且重写onChange()方法,以及我们在insert方法里面写了通知监听如果有其他应用访问insert方法,就会触发监听同志,就会执行注册监听时的onChange()方法。


0 0
原创粉丝点击