ContentProvider 内容提供者
来源:互联网 发布:山西统计局2016年数据 编辑:程序博客网 时间:2024/05/21 20:27
ContentProvider对外共享数据:
步骤
2. 定义匹配规则 指定主机名 + path code urimatcher content://
3. 通过静态代码块添加匹配规则
4. 一定要记得在清单文件配置内容提供者 不要忘记加authorities
public class PersonContentProvider extends ContentProvider{
public boolean onCreate()
public Uri insert(Uri uri, ContentValues values)
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public String getType(Uri uri)}
第四步需要在AndroidManifest.xml使用对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider
采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
ContentProvider类主要方法的作用:
public boolean onCreate()该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应用第一次访问它时才会被创建。
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类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
Uri介绍
Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的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")
UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。
掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
case 1
break;
case 2
break;
default://不匹配
break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,
假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
代码示例
package
com.itheima.transaction;
import
android.content.ContentProvider;
import
android.content.ContentValues;
import
android.content.UriMatcher;
import
android.database.Cursor;
import
android.database.sqlite.SQLiteDatabase;
import
android.net.Uri;
public
class
AccountProvider
extends
ContentProvider {
private
static
final
int
QUEYSUCESS =
0
;
// ctrl + shift + X(变大写) 变小写 + y
private
static
final
int
INSERTSUCESS =
1
;
private
static
final
int
UPDATESUCESS =
2
;
private
static
final
int
DELSUCESS =
3
;
//1 想使用内容提供者 必须定义 匹配规则 code:定义的匹配规则 如果 匹配不上 有一个返回码 -1
static
UriMatcher matcher =
new
UriMatcher(UriMatcher.NO_MATCH);
private
MyOpenHelper helper;
//2 我要添加匹配规则
static
{
//开始添加匹配规则
/**
* authority 主机名 通过主机名来访问我暴露的数据
* path 你也可以随意 写 com.itheima.contentprovider/query
* code 匹配码
*/
matcher.addURI(
"com.itheima.contentprovider"
,
"query"
, QUEYSUCESS);
//添加插入匹配规则
matcher.addURI(
"com.itheima.contentprovider"
,
"insert"
, INSERTSUCESS);
//添加更新匹配规则
matcher.addURI(
"com.itheima.contentprovider"
,
"update"
, UPDATESUCESS);
//添加删除匹配规则
matcher.addURI(
"com.itheima.contentprovider"
,
"delete"
, DELSUCESS);
}
@Override
public
boolean
onCreate() {
helper =
new
MyOpenHelper(getContext());
return
false
;
}
//Uri 范围比较大 不但可以指定 tel: 可以定义很多语法
@Override
public
Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
//传递过来的uri 是否和我们定义的匹配规则 匹配
int
match = matcher.match(uri);
if
(match == QUEYSUCESS ) {
//说明匹配成功
SQLiteDatabase db = helper.getReadableDatabase();
//获取数据库对象
Cursor cursor = db.query(
"info"
, projection, selection, selectionArgs,
null
,
null
, sortOrder);
//注意 这个地方 不要关闭 cursor 和 db
//大吼一声 数据库发生了改变
getContext().getContentResolver().notifyChange(uri,
null
);
return
cursor;
}
else
{
//匹配失败
throw
new
IllegalArgumentException(
"路径匹配失败"
);
}
}
@Override
public
String getType(Uri uri) {
return
null
;
}
@Override
public
Uri insert(Uri uri, ContentValues values) {
int
match = matcher.match(uri);
if
(match == INSERTSUCESS) {
//说明匹配成功
SQLiteDatabase db = helper.getReadableDatabase();
long
insert = db.insert(
"info"
,
null
, values);
//执行上面这句话 说明我的数据库内容 发生了变化 首先 要发送一条通知 说明 我发生改变
if
(insert>
0
) {
//数据库发生变化 发送一个通知
getContext().getContentResolver().notifyChange(uri,
null
);
}
Uri uri2 = Uri.parse(
"com.itheima.contentprovider/"
+insert);
return
uri2;
}
else
{
//匹配失败
throw
new
IllegalArgumentException(
"路径匹配失败"
);
}
}
@Override
public
int
delete(Uri uri, String selection, String[] selectionArgs) {
int
match = matcher.match(uri);
if
(match == DELSUCESS) {
//匹配成功
SQLiteDatabase db = helper.getReadableDatabase();
int
delete = db.delete(
"info"
, selection, selectionArgs);
if
(delete>
0
) {
//大吼一声 数据库发生了改变
getContext().getContentResolver().notifyChange(uri,
null
);
}
return
delete;
}
else
{
//匹配失败
throw
new
IllegalArgumentException(
"路径匹配失败"
);
}
}
@Override
public
int
update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int
match = matcher.match(uri);
if
(match == UPDATESUCESS) {
//匹配成功
SQLiteDatabase db = helper.getReadableDatabase();
int
update = db.update(
"info"
, values, selection, selectionArgs);
if
(update>
0
) {
//大吼一声 数据库发生了改变
getContext().getContentResolver().notifyChange(uri,
null
);
}
return
update;
}
else
{
//匹配失败
throw
new
IllegalArgumentException(
"路径匹配失败"
);
}
}
}
内容解析者ContentResolver
使用ContentResolver调用ContentProvider提供的接口,操作数据当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,
public Uri insert(Uri uri, ContentValues values)
该方法用于往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中获取数据。
这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。
使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse(
"content://cn.itcast.provider.personprovider/person"
);
//添加一条记录
ContentValues values =
new
ContentValues();
values.put(
"name"
,
"itcast"
);
values.put(
"age"
,
25
);
resolver.insert(uri, values);
//获取person表中所有记录
Cursor cursor = resolver.query(uri,
null
,
null
,
null
,
"personid desc"
);
while
(cursor.moveToNext()){
Log.i(
"ContentTest"
,
"personid="
+ cursor.getInt(
0
)+
",name="
+ cursor.getString(
1
));
}
//把id为1的记录的name字段值更改新为liming
ContentValues updateValues =
new
ContentValues();
updateValues.put(
"name"
,
"liming"
);
resolver.update(updateIdUri, updateValues,
null
,
null
);
监听ContentProvider中数据的变化
如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider 发生数据变化时调用
getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:
public
class
PersonContentProvider
extends
ContentProvider {
public
Uri insert(Uri uri, ContentValues values) {
db.insert(
"person"
,
"personid"
, values);
getContext().getContentResolver().notifyChange(uri,
null
);
}
}
系统就会调用ContentObserver的onChange()方法:
getContentResolver().registerContentObserver(Uri.parse(
"content://cn.itcast.providers.personprovider/person"
),
true
,
//true表示只要发出通知的Uri以方法第一个参数开头都能被监听到,否侧监听uri必须与发出通知的uri完全匹配才能被监听到
new
PersonObserver(
new
Handler()));
public
class
PersonObserver
extends
ContentObserver{
public
PersonObserver(Handler handler) {
super
(handler);
}
public
void
onChange(
boolean
selfChange) {
//此处可以进行相应的业务处理
}
}
实例代码
利用内容解析者备份短信
package
com.itheima.backupsms;
import
java.io.File;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
org.xmlpull.v1.XmlSerializer;
import
android.net.Uri;
import
android.os.Bundle;
import
android.os.Environment;
import
android.os.FileObserver;
import
android.app.Activity;
import
android.database.Cursor;
import
android.util.Xml;
import
android.view.Menu;
import
android.view.View;
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 点击按钮备份短信
*
* @param v
*/
public
void
backup(View v) {
try
{
// 1 初始化xml 序列化器
XmlSerializer serializer = Xml.newSerializer();
// 2初始化xml序列化器的 参数
File file =
new
File(Environment.getExternalStorageDirectory()
.getPath(),
"smsbackup.xml"
);
FileOutputStream fos =
new
FileOutputStream(file);
serializer.setOutput(fos,
"utf-8"
);
// 3 开始写 xml 头
serializer.startDocument(
"utf-8"
,
true
);
// 开始写 xml 根节点 smss
serializer.startTag(
null
,
"smss"
);
// 1 把我们关系的短信数据库里的内容 给 获取出来 我们要做的操作 就是通过内容解析者 把数据给查询出来
Uri uri = Uri.parse(
"content://sms"
);
Cursor cursor = getContentResolver().query(uri,
new
String[] {
"address"
,
"date"
,
"body"
},
null
,
null
,
null
);
while
(cursor.moveToNext()) {
// 写sms 节点
serializer.startTag(
null
,
"sms"
);
String address = cursor.getString(
0
);
String date = cursor.getString(
1
);
String body = cursor.getString(
2
);
//开始写 address 节点
serializer.startTag(
null
,
"address"
);
serializer.text(address);
serializer.endTag(
null
,
"address"
);
//开始写 date 节点
serializer.startTag(
null
,
"date"
);
serializer.text(date);
serializer.endTag(
null
,
"date"
);
//开始写 body 节点
serializer.startTag(
null
,
"body"
);
serializer.text(body);
serializer.endTag(
null
,
"body"
);
serializer.endTag(
null
,
"sms"
);
}
// 开始写 address date body
serializer.endTag(
null
,
"smss"
);
// 文档结束
serializer.endDocument();
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
利用内容解析者插入短信
//1 先拿到 内容解析器
Uri uri = Uri.parse(
"content://sms"
);
ContentValues values =
new
ContentValues();
values.put(
"address"
,
"110"
);
values.put(
"date"
, System.currentTimeMillis());
values.put(
"body"
,
"您的事犯了 请您马上来一趟"
);
getContentResolver().insert(uri, values);
利用内容解析者获取联系人数据
2. 去data表 根据 contact_id 去获取 mimetype data1的数据
3. 然后根据 mimetype_id 来区分数据类型
package
com.itheima.getcontactinfo.utils;
import
java.util.ArrayList;
import
java.util.List;
import
android.content.ContentResolver;
import
android.content.Context;
import
android.database.Cursor;
import
android.net.Uri;
import
com.itheima.getcontactinfo.domain.ContactInfo;
public
class
ContactUtils {
public
static
List<contactinfo> getContactInfos(Context context) {
List<contactinfo> contactLists =
new
ArrayList<contactinfo>();
// 1 首先 我要查询raw_contacts表 获取到 contact_id列
// (1)我如何查询 ?用 内容解析者 path
Uri uri = Uri.parse(
"content://com.android.contacts/raw_contacts"
);
Uri datauri = Uri.parse(
"content://com.android.contacts/data"
);
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(uri,
new
String[] {
"contact_id"
},
null
,
null
,
null
);
while
(cursor.moveToNext()) {
// 获取到contact_id 的值
String contact_id = cursor.getString(
0
);
System.out.println(
"contact_id--"
+ contact_id);
// 有个小细节注意一下 我要判断 contact_id 是否为空
if
(contact_id !=
null
) {
ContactInfo info =
new
ContactInfo();
info.setId(contact_id);
// 2去data表 根据 contact_id 去获取 mimetyple_id列 data1 列
Cursor dataCursor = resolver.query(datauri,
new
String[] {
"mimetype"
,
"data1"
},
"raw_contact_id=?"
,
new
String[] { contact_id },
null
);
while
(dataCursor.moveToNext()) {
String mimetype = dataCursor.getString(
0
);
// 获取到mimeytype
String data1 = dataCursor.getString(
1
);
// 3 然后根据 mimetype类型 来区分数据类型
if
(
"vnd.android.cursor.item/email_v2"
.equals(mimetype)) {
info.setEmail(data1);
}
else
if
(
"vnd.android.cursor.item/name"
.equals(mimetype)) {
info.setName(data1);
}
else
if
(
"vnd.android.cursor.item/phone_v2"
.equals(mimetype)) {
System.out.println(
"data---电话号码-"
+ data1);
info.setPhone(data1);
}
}
dataCursor.close();
contactLists.add(info);
// 把info信息存到集合中
}
}
cursor.close();
return
contactLists;
}
}
</contactinfo></contactinfo></contactinfo>
package
com.itheima.getcontactinfo.domain;
public
class
ContactInfo {
private
String id;
private
String name;
private
String phone;
private
String email;
public
String getId() {
return
id;
}
public
void
setId(String 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
String getEmail() {
return
email;
}
public
void
setEmail(String email) {
this
.email = email;
}
@Override
public
String toString() {
return
"ContactInfo [id="
+ id +
", name="
+ name +
", phone="
+ phone
+
", email="
+ email +
"]"
;
}
}
利用内容解析者插入联系人
2. 往data表插入数据 根据mimetype contact_id 往里插入数据
package
com.itheima.insert.contact;
import
android.net.Uri;
import
android.os.Bundle;
import
android.app.Activity;
import
android.content.ContentValues;
import
android.database.Cursor;
import
android.view.Menu;
import
android.view.View;
import
android.widget.EditText;
public
class
MainActivity
extends
Activity {
private
EditText et_name;
private
EditText et_phone;
private
EditText et_email;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1找到我们关心的控件
et_name = (EditText) findViewById(R.id.et_name);
et_phone = (EditText) findViewById(R.id.et_phone);
et_email = (EditText) findViewById(R.id.et_email);
}
/**
* 保存联系人的信息
* @param v
*/
public
void
click(View v){
//1 要先拿到 edittext的值
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();
String email = et_email.getText().toString().trim();
//2 往 raw_contacts里插入一条数据 拿到内容解析者
Uri uri = Uri.parse(
"content://com.android.contacts/raw_contacts"
);
Uri datauri = Uri.parse(
"content://com.android.contacts/data"
);
ContentValues values =
new
ContentValues();
// 插入数据之前 我要先查询 一下 raw_contacts 表一共有多少行的数据
Cursor cursor = getContentResolver().query(uri,
null
,
null
,
null
,
null
);
int
count = cursor.getCount();
//获取到一共有多少行
int
contact_id = count +
1
;
values.put(
"contact_id"
, contact_id);
getContentResolver().insert(uri, values);
// 3 往data 表插入数据
ContentValues nameValues =
new
ContentValues();
nameValues.put(
"data1"
, name);
nameValues.put(
"mimetype"
,
"vnd.android.cursor.item/name"
);
nameValues.put(
"raw_contact_id"
, contact_id);
getContentResolver().insert(datauri, nameValues);
ContentValues phoneValues =
new
ContentValues();
phoneValues.put(
"data1"
, phone);
phoneValues.put(
"mimetype"
,
"vnd.android.cursor.item/phone_v2"
);
phoneValues.put(
"raw_contact_id"
, contact_id);
getContentResolver().insert(datauri, phoneValues);
ContentValues emailValues =
new
ContentValues();
emailValues.put(
"data1"
, email);
emailValues.put(
"mimetype"
,
"vnd.android.cursor.item/email_v2"
);
emailValues.put(
"raw_contact_id"
, contact_id);
getContentResolver().insert(datauri, emailValues);
}
}
利用监听和内容解析者监听短信
package
com.itheima.smslistener;
import
android.net.Uri;
import
android.os.Bundle;
import
android.os.Handler;
import
android.app.Activity;
import
android.database.ContentObserver;
import
android.database.Cursor;
import
android.view.Menu;
public
class
MainActivity
extends
Activity {
private
Uri uri;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1注册一个内容观察者
uri = Uri.parse(
"content://sms"
);
getContentResolver().registerContentObserver(uri,
true
,
new
MyObserver(
new
Handler()));
}
private
class
MyObserver
extends
ContentObserver{
public
MyObserver(Handler handler) {
super
(handler);
}
@Override
public
void
onChange(
boolean
selfChange) {
//当短信的数据库发生了变化 我就去取出所有短信的内容
Cursor cursor = getContentResolver().query(uri,
new
String[]{
"address"
,
"body"
,
"date"
},
null
,
null
,
null
);
while
(cursor.moveToNext()){
String address = cursor.getString(
0
);
String body = cursor.getString(
1
);
String date = cursor.getString(
2
);
System.out.println(
"address---"
+address+
"--body:"
+body);
}
super
.onChange(selfChange);
}
}
- ContentProvider内容提供者
- Android ContentProvider(内容提供者)
- ContentProvider 内容提供者
- ContentProvider内容提供者(一)
- ContentProvider内容提供者(二)
- ContentProvider 内容提供者
- android内容提供者ContentProvider
- Android--- ContentProvider(内容提供者)
- ContentProvider内容提供者
- ContentProvider(内容提供者)
- ContentProvider(内容提供者)
- ContentProvider内容提供者
- ContentProvider 内容提供者
- ContentProvider 内容提供者
- contentprovider 自定义内容提供者
- ContentProvider内容提供者
- ContentProvider 内容提供者
- ContentProvider 内容提供者
- 【数论】玲珑oj 1145
- FFMPEG学习【ffmpeg工具】
- C语言——实例018 s=a+aa+aaa+aaaa+aa...a
- LTE之3GPP_协议下载_协议命名
- Android杂谈--打开文件的Intent及使用
- ContentProvider 内容提供者
- HttpURLConnection ----GET请求 和 POST请求:
- 数据库sql语句练习题
- D3 笔记六:Update、Enter、Exit
- Redis入门及在商城案例中的使用
- 使用shell 脚本实现 希尔排序
- linux睡眠和唤醒的一个例子
- leetCode 1. Two Sum
- python logging的使用