ContentProvider实现数据共享

来源:互联网 发布:手机电子书软件 编辑:程序博客网 时间:2024/05/17 07:44

ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。Android已经为常见的一些数据提供了默认的ContentProvider比如联系人、短信、图片、音视频等

当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数 据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数 据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。

使用ContentProvider我们经常会用到三个类:

ContentProvider、Uri、ContentResolver


实现自定义的ContentProvider

准备数据----以数据库为例

public class MySqliteHelper extends SQLiteOpenHelper {
    public MySqliteHelper(Context context) {
        super(context, "test.db", null, 1, null);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE person(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, salary INTEGER)");
        Log.e("MySqliteHelper","onCreate....");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS person");
        onCreate(db);
    }
}


利用ContentProvider提供数据库操作接口

1、 定义自己的ContentProvider类,重写以下方法

  public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。

安装应用并第一次运行的时候才会回调onCreate, 在此创建helper

  public Uri insert(Uri uri, ContentValues values):该方法用于供外部应用往ContentProvider添加数据。

public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于供外部应用从ContentProvider删除数据。

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于供外部应用更新ContentProvider中的数据。

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于供外部应用从ContentProvider中获取数据。

public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。用不到直接返回null

 

2. ContentProvider是Android中的四大组件之一 ,所以需要在AndroidManifest.xml文件中进行注册。注册成功之后,其他应用程序就可以通过该Uri来访问。注册的时候,与注册Activity类似

      <provider

            android:name="com.qianfeng.MyProvider"   //自定义的ContentProvider的类名

            android:authorities="com.qianfeng.provider"  //Uri标示,相当于当前网站的主机

            android:exported="true" >  //true代表暴露给另外的程序


在需要获得数据的应用程序中使用ContentResolver

1、 获得ContentResolver对象:

调用Context对象的getContentResolver()方法,获取当前应用默认的ContentResolver对象。

2、 获得ContentProvider对象之后,就可以调用他的下面的方法来操作数据:

a:   insertUrivalues)   插入数据

b:  deleteuri, where, selectionArgs)  删除数据

c:  update…)  更新数据

d:  query(…) 查询数据

egetType暂时不管

注意:ContentProvider负责暴露数据、ContentResolver操作暴露出来的数据



ContentResolver和ContentProvider的深层理解




3.Uri类的介绍和Uri字符串的定义



(一)Uri的简介

android中可以为系统的每一个资源给起一个名字,这个名字就是这个资源的Uri

ContentProvider中使用的Uri非常类似于我们以前访问网站使用Url

(二)Uri的结构

一个Uri

content://qianfeng.com.providers/abc/2

主要可以分为三部分:

1content://   ContentProvider规定好的。协议部分,表示ContentProvider使用的协议必须是content://

2qianfeng.com.providers   :   URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称

 

前两部分必须有----匹配清单中的authorities属性

File://

Tel://

http://

 

3abc  :  路径。通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;ContentProvider怎么定义,访问的时候就要怎么写。

42  如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部

 

 

为了将字符串转换成Uri,可以使用Uri中的静态方法:

Uri  uri = Uri.parse(“”);

 

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
1、要操作person表中id10的记录,可以构建这样的路径:/person/10
2、要操作person表中id10的记录的name字段, person/10/name
3、要操作person表中的所有记录,可以构建这样的路径:/person
4、要操作xxx表中的记录,可以构建这样的路径:/xxx
5、当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
6.* 代表通配所有字符

7.#代表通配数字

 

(三)Uri的匹配----为了验证uri传入得是否正确,也为了针对不同的请求做出不同的响应

因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。

Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。

ContentURI的全局匹配流程图

到匹配的第二步,我们已经匹配到了content://com.example.transportionprovider,那后面的/trains/122的匹配工作就只有交由ContentProvider来处理了。

在ContentProvder中的匹配是利用UriMatcher来完成的!

A:UriMatcher:

UriMatcher的匹配工作的第一步就是先将所需要的匹配的URI使用addURI()添加到UriMatcher中,这个步骤是外界还没有访问数据的时候就要作的

public void addURI(String authority, String path, int code)

其中第一个参数authority:就是URI对应的authority

path:就是我们在URI中 authority后的那一串

code:表示匹配成功以后的返回值;

 

  第二步是匹配Uri,使用方法int match(Uri uri)    

当有人调用当前ContentProvider的CRUD的时候,我们可以使用这个方法来进行传来的Uri和我们注册的Uri匹配,如果成功就执行,否则不执行。

注意:至于到底需要为UriMatcher对象注册多少个Uri,则取决于系统的业务需求。

具体使用方式是:

a.在ContentProvider中添加以下代码注册Uri:

private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 

static{

//当有Uri匹配的时候返回1   *可以匹配任意的字符串  #可以匹配任意的整型数字

matcher.addURI(AUTHORITY, "person", 1); //   content://com.qianfeng.person.provider/person

matcher.addURI(AUTHORITY, "user", 2);  // content://com.qianfeng.person.provider/user

   matcher.addURI(AUTHORITY, "human", 3); //content://com.qianfeng.person.provider/human

}

b.在query()、insert()、update()、delete()等方法中添加以下代码来检测Uri

if(matcher.match(uri) == 1){

     db.insert("person", null, values);

     ....

   }

如果不匹配,抛出异常:

 throw new IllegalArgumentException("Unknown URI " + uri);  

 

  B: ContentUris:

        这个类是一个操作Uri字符串的工具类,主要是拼接Uri字符串用。

        withAppendedId(uri, id)   用于为路径加上id部分

        parseId(uri)   用于从指定的Uri中解析出所包含的id


三、内容观察者----了解------Loader

 工作中,如果开启线程不断的查询某个数据库的内容是否发生变化,会导致系统的开销很大,利用ContentObserver可以完美的解决该问题。

ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,当ContentObserver所观察的Uri发生变化时,便会触发它。熟悉Content Provider(内容提供者)的应该知道,我们可以通过UriMatcher类注册不同类型的Uri,我们可以通过这些不同的Uri来查询不同的结果。那么我们也可以监视Uri所指定的数据的变化情况

注册观察者

ContentResolver类中注册内容观察者的方法原型如下:

public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)

功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。

参数1:uri  要观察的Uri(需要在UriMatcher里注册,否则该Uri也没有意义了)

参数2:notifyForDescendents  为false 表示精确匹配,即只匹配该Uri

                             为true 表示可以同时匹配其派生的Uri,

      举例如下:

      假设UriMatcher 里注册的Uri共有一下类型:

      1 、content://com.qin.cb/student (学生)

      2 、content://com.qin.cb/student/# 

      3、 content://com.qin.cb/student/schoolchild(小学生,派生的Uri)

     假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的 Uri 为content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到,但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。

参数3:observer  定义类继承ContentObserver, 重写onChange()方法,构建该类实例传入进行注册,在收到数据改变通知之后, 会自动执行onChange()方法

 

例如在访问数据库的相关应用程序中添加:

getContentResolver().registerContentObserver(uri,true,new MyObserver());

public class MyObserver extends ContentObserver {

public MyObserver(Handler handler) {

super(handler);

// TODO Auto-generated constructor stub

}

public MyObserver() {

// TODO Auto-generated constructor stub

super(new Handler());

}

@Override

public void onChange(boolean selfChange) {

// 此处写当数据变化的时候的处理代码

}

}

通知观察者

注册观察者之后, 需要在ContentProvider中进行通知, 观察者才能收到, 使用ContentResolver.notifyChange()方法可以通知数据的改变

例如在contentprovider的数据改变的方法中添加:

getContext().getContentResolver().notifyChange(uri, null);

 

 

 

四、SearchView的使用

xml中主要配置有四个属性,如下:

android:iconifiedByDefault表示搜索图标是否在输入框内。true效果更佳

android:imeOptions设置IME options,即输入法的回车键的功能,可以是搜索、下一个、发送、完成等等。这里actionSearch表示搜索

android:inputType输入框文本类型,可控制输入法键盘样式,如numberPassword即为数字密码样式

android:queryHint输入框默认文本

 

主要方法:

setOnCloseListener(SearchView.OnCloseListener listener)表示注册点击取消按钮时的listener,默认点击搜索输入框

setOnQueryTextListener(SearchView.OnQueryTextListener listener)表示输入框文字变化的listener,包括public boolean onQueryTextSubmit(String query)和public boolean onQueryTextChange(String newText)两个方法

 

 



0 0
原创粉丝点击