1、为什么需要内容提供者?(contentProvider)
[1] 如何创建一个数据库? 创建一个类继承SqliteOpenHelper
[2] sqlite3 打开数据库
[3] chmod 修改文件权限
需求:从当前应用获取其他应用的数据库
(1) 使用SqliteDatabase的静态方法 openDatabase(String path,Factory,mode);
参数说明
path:数据库所在的位置
Factory:游标工厂
mode:打开的模式,使用SqliteDatabase的静态常量就可以了
[4] 使用内容提供者获取私有的数据库
2、内容提供者原理
[1] 内容提供者(ContentProvider)将内容进行封装提供出来,其他的应用都是通过内容的解析者(ContentResolve)来获取
3、实现内容提供者的步骤
[1] 定义一个类继承ContentProvider
public class ItProvider extends ContentProvider
[2] 在清单文件中配置内容提供者 必须加一个属性authorities值为自定义字符串
<provider
android:exported="true"
android:authorities="com.young.test"
android:name="com.db.ItProvider"/>
如果不加exported属性,会报
java.lang.
SecurityException: Permission Denial: opening provider com.db.ItProvider from ProcessRecord{528581e0 6355:com.accessotherdb/u0a10053} (pid=6355, uid=10053) that is not
exported from uid 10052
[3] 定义一个路径匹配器 UriMatcher
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //
UriMatcher.NO_MATCH代表匹配不成功返回-1
[4] 定义一个静态代码块,添加匹配规则 addURI
static{
uriMatcher.addURI("com.young.test","query",QUERYSUCCESS);
}
[5] 实现相应的匹配模块
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
if (uriMatcher.match(uri) == QUERYSUCCESS){
openHelper = new MyOpenHelper(getContext());
db = openHelper.getReadableDatabase();
Cursor it = db.query("It", strings, s, strings1, null, null, s1);
return it;
}
return null;
}
[6] 在需要的app中调用
(1) 直接使用上下文拿到resolve(getContentResolve)
ContentResolver contentResolver = getContentResolver();
(2) 然后就拿着resolve开始解析
Uri uri = Uri.parse("content://com.young.test/query"); //content://相当于url里面的http://协议,是谷歌定义好的
Cursor query = contentResolver.query(uri, null, null, null, null);
(3) 下一步就是拿到结果集合,开始展示
while(query.moveToNext()){
Log.d("name",query.getString(1));
Log.d("phone",query.getString(2));
}
4、备份短信案例
[1] 短信备份使用的是系统提供的sms应用下的provider,所以只需要获取内容解析者就可以了
public void backup(View view){
ContentResolver resolver = getContentResolver();
/* sURLMatcher.addURI("sms", null, SMS_ALL);*/
Uri uri = Uri.parse("content://sms/"); //在这里sms/后面不加通过源码可以知道这是查询所有的方式
//下面的String类型,可以使用一个引号?
Cursor cursor = resolver.query(uri, new String[]{"address","date","body"}, null, null, null);
while(cursor.moveToNext()){
Log.d("address",cursor.getString(0));
Log.d("data",cursor.getString(1));
Log.d("body",cursor.getString(2));
}
}
[2] 将这些数据保存到sd卡进行文件备份,使用xml序列化器
//[3] 开始写文档
serializer.startDocument("utf-8",true);
serializer.startTag(null,"smss");
/* sURLMatcher.addURI("sms", null, SMS_ALL);*/
Uri uri = Uri.parse("content://sms/"); //在这里sms/后面不加通过源码可以知道这是查询所有的方式
//下面的String类型,可以使用一个引号?
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, new String[]{"address","date","body"}, null, null, null);
while(cursor.moveToNext()){
serializer.startTag(null,"sms");
serializer.startTag(null,"address");
serializer.text(cursor.getString(0));
serializer.endTag(null,"address");
serializer.startTag(null,"date");
serializer.text(cursor.getString(1));
serializer.endTag(null,"date");
serializer.startTag(null,"body");
serializer.text(cursor.getString(2));
serializer.endTag(null,"body");
serializer.endTag(null,"sms");
}
serializer.endTag(null,"smss");
serializer.endDocument();
5、读取联系人案例
[1] 三张重要的表 data1里面存的是所有联系人的信息
[2] data里面的raw_contact_id实际上是raw_contact里面的contact_id
[3] data表里面的mimetype_id实际对应于mimetype列
步骤
[1] 先读取raw_contact表 读取contract_id字段,从而知道有多少个联系人
[2] 根据contract_id读取data1列 和 mimetype列
//[1] 首先读取raw_contact表里面的contact_id列,就可以知道有多少联系人
ContentResolver resolver = getContentResolver();
Uri contactUri = Uri.parse("content://com.android.contacts/raw_contacts");//content内容分别从contactProvider的AndroidManfest.xml中取出authorities,然后去源码页取出path
Cursor cursor = resolver.query(contactUri, new String[]{"contact_id"}, null, null, null);
while(cursor.moveToNext()){
//在查找联系人个数后将每个联系人的信息从data表里面的data1和mimetype里面取出来
ContentResolver resolver1 = getContentResolver();
Uri dataUri = Uri.parse("content://com.android.contacts/data");
Cursor cursor1 = resolver1.query(dataUri, new String[]{"data1", "mimetype"}, "raw_contact_id=?", new String[]{cursor.getString(0)}, null); //将每个联系人的所有数据取出来进行展示
while (cursor1.moveToNext()){
String data1 = cursor1.getString(0);
String mimetype = cursor1.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)) { //进行mimetype类型判定
System.out.println("name:"+data1);
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
System.out.println("phone:"+data1);
}else if("vnd.android.cursor.item/email_v2".equals(mimetype)){
System.out.println("email:"+data1);
}
}
[2] 需要权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
[3] 对于安卓手机,当用户删除掉联系人,只是将raw_contact_id的相应id置为null,所以可以恢复数据
6、插入联系人
[1] 插入要影响的表有raw_contact表和data表,影响的列有contact_id(raw_contact)和mimetype、data1、contact_id(data)
[2] 步骤:
(1) 查询raw_contact表中的数据的条数count,将要插入的id为count+1
(2)将id插入到raw_contact表的contact_id中
(3) 将name,phone,email等插入到data表的data1列,并且标明数据属于哪一个id和哪一个mimetype
public void insert(View view){
//[1] 获取数据
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();
String email = et_email.getText().toString().trim();
//[2] 查询raw_contact表中的数据条数
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Cursor cursor = resolver.query(uri, null, null, null, null);
int count = cursor.getCount();
int contact_id = count + 1;
//[3] 将contact_id添加进去
ContentResolver insert_id = getContentResolver();
ContentValues idValues = new ContentValues();
idValues.put("contact_id",contact_id);
insert_id.insert(uri,idValues);
//[4] 将其他的数据添加到data表中
Uri dataUri = Uri.parse("content://com.android.contacts/data");
ContentResolver dataResolver = getContentResolver();
ContentValues nameValues = new ContentValues();
//设置信息类型
nameValues.put("mimetype","vnd.android.cursor.item/name");
//设置信息id
nameValues.put("raw_contact_id",contact_id);
//设置信息主体
nameValues.put("data1",name);
dataResolver.insert(dataUri,nameValues);
ContentValues phoneValues = new ContentValues();
phoneValues.put("mimetype","vnd.android.cursor.item/phone_v2");
phoneValues.put("raw_contact_id",contact_id);
phoneValues.put("data1",phone);
getContentResolver().insert(dataUri,phoneValues);
ContentValues emailValues = new ContentValues();
emailValues.put("mimetype","vnd.android.cursor.item/email_v2");
emailValues.put("raw_contact_id",contact_id);
emailValues.put("data1",email);
getContentResolver().insert(dataUri,emailValues);
}
7、内容观察者(了解)
需求:如果provider的内容被修改了,那么第三个应用要立刻知道,这个就是内容观察者
【1】 在完成数据库的操作后,发送给一个消息
getContentResolver().notifyChange(uri,null);
【2】 然后在想要接收提醒的应用中写
getContentResolver().registerContentObserver(uri,true,new MyContentObsever(new Handler()));
意图里面可以传序列化对象,serializerable(序列化存储)和parcelable(序列化到内存)