Provider是Android四大组件之一,是一种数据共享机制(封装数据的接口规范)。是一个数据库的代理,实现跨应用间的数据共享,类似于window服务本身不负责启动和关闭,多个应用可同时访问统一provider。
主要类:
ContentProvider 类
ContentProvider 对象将程序内部数据向其他程序公开
ContentResolver 类
其他程序通过ContentResolver 对象对程序内部数据进行CRUD操作
ContentProvider 分类:
1.使用别人的provider 比如电话本,短信,媒体 这些数据系统底层使用xxx.db数据库封装为ContentProvider 接口
2.应用创建的provider 程序员自定义的,可提供给别人使用
如何定义自己的provider
步骤:
1.继承ContentProvider 定义子类
2.重写6个方法(所有方法都需要uri,每个ContentProvider 都提供对外公共uri) ContentProvider 将共享数据定义为uri
public class MenusProvider extends ContentProvider{
@Override
public boolean onCreate() {
// 底层数据库初始化
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}
@Override //要实现该方法必须完成
//1.定义MIME类型
//2.定义URI字符串
//3.用urimather建立code和uri映射
//4.用code来映射不同MIEM类型
public String getType(Uri uri) {
// 返回MIME类型,一般用静态块来完成
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}
uri代表地址,解决如何表示数据的问题.
3.声明CONTENT_URI公共的静态常量,实现UriMathcer的绑定
当自定义provider需要告诉使用ContentProvider 的人用到那些uri
UriMatcher类 将uri和MIME绑定的
ContentUris类 将uri解析/生成
4.实现provider底层封装到sqlite框架中.
4.1 onCreat() 初始化数据库 SQLiteOpenHelper辅助类
4.2 provider重写提供CRUD操作方法,如何使用uri
如:
content://myfs.pub.menusprovider/menus/2
list={“menus”,”2”}
5.注册provider,在AndroidManifest.xml文件< application>< /application>标签中(四大组件都需要注册)
<provider
android:name="com.robin.myprovider.MenusProvider"
<!--Provider子类全名 -->
android:authorities="myfs.pub.menusprovider"
<!--指定授权者(自定义字符串) -->
android:exported="true"
<!-- 跨应用共享数据 设置为true默认为false
表示该provider能够被其他应用程序组件调用 -->
>< /provider>
6.测试provider
本地测试provider
远程测试provider
报错:
Installation error: INSTALL_FAILED_CONFLICTING_PROVIDER
表示系统中已经有同名的provider,调试时卸载重装即可。
使用->观察者模式
作用:监听ContentProvider 数据改变
ContentObserver 类
当ContentProvider 共享出来后,有时应用需要实时获得ContentProvider 共享数据的变化需要利用ContentObserver对象来实现。
实现步骤:
1.provider端的CRUD操作改变数据时调用resolver. notifyChange()方法
2.使用provider端要注册ContentObserver 对象
2.1 定义ContentObserver 子类重写onChange(boolean selfChange)方法
2.2 构造子类对象并注册给使用provider端的ContentResolver对象
如:cr.registerContentObserver(Menus.CONTENT_URI, notifyForDescendents, observer);
参数:
Menus.CONTENT_URI:监听CP的uri –> content://authority/menus
notifyForDescendents:true 表示该uri下所有的数据变化都监听
observer:false 表示只是监听uri数据变化
示例:
1.定义数据bean类
文件名Menus.java
package com.ql.providerdemo;
import android.net.Uri;
/**
* 定义provider需要的相关数据 MIME类型
* @author qinlang
*
*/
public class Menus {
// 以下定义provider的MIME类型常量
public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";// MIME类型 多条
public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";// 单条
//以上两条为android规定的
public static final String MIME_ITEM = "vnd.pub.menus";// 自定义MIME类型字符串
// 将固定前缀+自定义字符串生成两个类型
public static final String MIME_TYPE_SINGLE = MIME_ITEM_PREFIX + "/"
+ MIME_ITEM;
public static final String MIME_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/"
+ MIME_ITEM;
// 用来定义uri常量 content://<authority>/<data path>/..../id
public static final String AUTHORITY = "myfs.pub.menusprovider";// 授权者 表示用哪个provider,要跟清单文件中一致
public static final String PATH_SINGLE = "menus/#"; // (menus:数据库表名)路径下单条记录 #代表数字id
public static final String PATH_MULTIPLE = "menus";// 路径下多条记录 数据库将对应表名
public static final String PATH_MULTIPLE_NAME = "menus/*"; // *代表文本 例如按名称访问等
// 组合成所需要的uri字符串
public static final String CONTENT_URI_STRING = "content://" + AUTHORITY
+ "/" + PATH_MULTIPLE;
// 将uri字符串转换为uri对象
public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);
// 以上就完成自定义provider所需的uri和MIME类型的定义
// 涉及sqlite底层实现的内容
public static final String CREAT_TABLE = "create table menus(id integer primary key autoincrement ,name varchar(50),price integer)";
public static final String DBNAME = "pub.db";//数据库名
public static final String TABLENAME = "menus";//表名
public static final int DB_VER = 1;//数据库版本,用于升级用
//常量字符串,对应数据库中的字段
public static final String KEY_ID = "id";
public static final String KEY_NAME = "name";
public static final String KEY_PRICE = "price";
public static final String[] COLUNMS = { KEY_ID, KEY_NAME, KEY_PRICE };
private int id;
private String name;
private int price;
public Menus() {
}
public Menus(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "id:" + id + " | name:" + name + " | price:" + price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
2.创建ContentProvider的子类,内容提供类
文件名:MenusProvider.java
package com.ql.providerdemo;
import android.content.ContentProvider;
import android.content.ContentUris;