1.谷歌为什么研发内容提供者
1.activity 代表页面 2.广播接收者.外拨电话事件 方便程序员开发更多的应用程序.3.service:播放音乐 4.内容提供者:暴漏私有的数据库给其他应用使用.
2.chmod 777 itheima.db 修改文件权限
2.内容提供者工作原理
代码实现
1.在应用1的内部定义一个内容提供者
URI:统一资源标示符 也表示一个路径 这个路径可以自己定义
URL:统一资源定位符
www.baidu.com
2.在内容提供者内部定义一个urimatcher 并且定义一个静态代码块添加匹配规则
//1.定义一个urimatcher(路径匹配器)
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int QUERYSUCESS = 1;
//2.定义一个静态代码块 特点:随着类的加载而加载 只执行一次.
static {
/**
* 3.添加路径 参数1:要和你清单文件配置参数一样 参数3 匹配码
* http://www.baidu.com/tieba 通过这个路径代表访问百度贴吧
* content://com.itheima/query 定义含义
*/
sURIMatcher.addURI("com.itheima","query",QUERYSUCESS);
}
3.把增删改查方法暴漏出去
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
//1.匹配其他应用传递过来的uri路径
int code = sURIMatcher.match(uri);
if (code == QUERYSUCESS){
//2.说明路径匹配成功 把query方法实现 对数据库进行查询操作--->获取sqlteDatabase实例
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
//3.对数据库实现查询操作
Cursor cursor = db.query("info", projection, selection, selectionArgs, sortOrder, null, null);
//4.把cursor返回
return cursor;
}else{
//说明路径匹配失败
throw new IllegalArgumentException("哥们 路径匹配失败");
// return null;
}
}
4.其他应用程序提供内容解析者操作数据库
public void click(View view) {
//0.定义Uri
Uri uri = Uri.parse("content://com.itheima/query");
//1.获取内容解析者
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
//2.把张三 李四信息查询出来
if (cursor!=null){
while (cursor.moveToNext()){
String id = cursor.getString(0);
String name = cursor.getString(1);
String phone = cursor.getString(2);
String money = cursor.getString(3);
System.out.println("第二222个应用id:"+id+"----:"+name+"----:"+phone);
}
}
}
3.短信备份:
代码实现过程
1.提供内容解析者把短信数据取出来
{
//0.准备访问短信数据库的uri
Uri uri = Uri.parse("content://sms/");
//1.读取短信数据库的内容 由于短信数据库系统已经通过内容提供者暴漏出来 所以我们可以直接通过内容解析者来查询数据库
Cursor cursor = getContentResolver().query(uri, new String[]{"address", "date", "body"}, null, null, null);
//2.把对应的数据取出来
while (cursor.moveToNext()){
String address = cursor.getString(0);
String date = cursor.getString(1);
String body = cursor.getString(2);
System.out.println("address:"+address+"---"+date+"===="+body);
}
}
2.使用xml序列化把数据保存到xml文件中
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击按钮备份系统短信 --->xml描述数据
public void click1(View view) {
try {
//1.获取一个xml序列化器
XmlSerializer serializer = Xml.newSerializer();
//1.1 通过文件输出流指定文件生成位置
File file = new File(getFilesDir().getPath(),"smsbackup.xml");
FileOutputStream fos = new FileOutputStream(file);
//2.告诉序列化器 生成一个xml文件
serializer.setOutput(fos,"utf-8");
//3.根据xml语法生成xml文件 文档声明
serializer.startDocument("utf-8",true);
//4.生成xml根标签
serializer.startTag(null,"smss");
//5.循环生成子标签 sms标签生成几个 准备访问短信数据库的uri
Uri uri = Uri.parse("content://sms/");
//6.读取短信数据库的内容 由于短信数据库系统已经通过内容提供者暴漏出来 所以我们可以直接通过内容解析者来查询数据库
Cursor cursor = getContentResolver().query(uri, new String[]{"address", "date", "body"}, null, null, null);
//7.把对应的数据取出来
while (cursor.moveToNext()){
String address = cursor.getString(0);
String date = cursor.getString(1);
String body = cursor.getString(2);
//8.生成xml的sms标签
serializer.startTag(null,"sms");
//9.生成address标签
serializer.startTag(null,"address");
serializer.text(address);
serializer.endTag(null,"address");
//10.生成date标签
serializer.startTag(null,"date");
serializer.text(date);
serializer.endTag(null,"date");
//11.生成body标签
serializer.startTag(null,"body");
serializer.text(body);
serializer.endTag(null,"body");
serializer.endTag(null,"sms");
}
serializer.endTag(null,"smss");
serializer.endDocument();
Toast.makeText(this, "备份成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "备份失败", Toast.LENGTH_SHORT).show();
}
-
}
4.生成虚拟短信
//点击按钮 实现短信还原的逻辑 ---->就是xml解析 把数据解析出来--->插入到短信数据库
public void click2(View view) {
//0.把xml里面的数据解析出来 TODO xml解析的逻辑
//1.由于系统短信数据库 系统已经通过内容提供者暴漏出来 所以我们可以直接通过内容解析者操作数据库
Uri uri = Uri.parse("content://sms/"); //张三 回家 小伙伴
//2.创建一个ContentValues
ContentValues values = new ContentValues();
values.put("address","95555"); //招商银行客服
values.put("date",System.currentTimeMillis());
values.put("body","您好,请的银行卡余额为-500000元");
//3.把数据插入到短信数据库
getContentResolver().insert(uri,values);
}
}
5.查询联系人
微信 QQ 陌陌....
联系人相关的三张表
1.data表 data1列 存的是联系人所有的信息(包括 电话 邮箱 姓名 地址)
2.raw_contacts表 contact_id列 表示应用一共有几条联系人
3.mimetype 表 id字段 用来区分联系人信息
查询联系人的步骤
[1]先查询
raw_contacts 的contact_id字段 就知道一共有几条联系人
[2]在查询data表 先查询data1字段和mimetype_id字段
Invalid column mimetype_id() :报mimetype_id列无效 1:列名写错了 2.表中没有这列.
public class QueryContactUtils {
//查询联系人的业务方法
public static List<Contact> getContact(Context context){
List<Contact> lists = new ArrayList<>();
//0.准备查询联系人数据库的路径
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
//1.先查询raw_contacts 的contact_id字段 由于联系人数据库系统已经通过内容提供者暴漏出来 所以我们可以直接通过内容解析者操作数据
Cursor cursor = context.getContentResolver().query(uri, new String[]{"contact_id"}, null, null, null);
while (cursor.moveToNext()){
Contact contact = new Contact();
String contact_id = cursor.getString(0);
System.out.println("contact_id:"+contact_id);
//1.1 把data表中所有的列都查询出来
//2.根据联系人id 取查询data表 data1列和mimetype_id列
Cursor dataCursor = context.getContentResolver().query(dataUri, new String[]{"data1", "mimetype"}, "raw_contact_id=?", new String[]{contact_id}, null);
while (dataCursor.moveToNext()){
String data1 = dataCursor.getString(0);
String mimetype = dataCursor.getString(1);
//3.通过字符串判断data1数据类型
if ("vnd.android.cursor.item/email_v2".equals(mimetype)){
System.out.println("邮箱:"+data1);
contact.setEmail(data1);
}else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)){
System.out.println("电话:"+ data1);
contact.setPhone(data1);
}else if ("vnd.android.cursor.item/name".equals(mimetype)){
System.out.println("姓名:"+data1);
contact.setName(data1);
}
}
lists.add(contact);
}
return lists;
}
}
6.通过内容解析者向联系人数据库插入联系人
插入联系人的步骤
[1]先往
raw_contacts
表插入数据 更新contact_id
[2]在往data表里面插入数据
{
//2.获取name phone 和 email
String email = et_email.getText().toString().trim();
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
//2.0 插入数据之前 应该先查询一共有几条联系人 数量+1 = contact_id的值
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
int count = cursor.getCount();//获取表中行数
int contact_id = count + 1;
//2.1 通过values更新contact_id字段
ContentValues values = new ContentValues();
values.put("contact_id",contact_id);
//3.把email name phone插入到联系人数据库 由于联系人数据库系统已经通过内容提供者暴漏出来 所以我们可以直接通过内容解析者操作数据库
getContentResolver().insert(uri,values);
//4.先更新name的数据
ContentValues nameVaues = new ContentValues();
nameVaues.put("data1",name); //把name数据更新到data1列
nameVaues.put("raw_contact_id",contact_id); //告诉系统新插入的name属于哪个联系人
nameVaues.put("mimetype","vnd.android.cursor.item/name");
//5.把name 更新到data表
getContentResolver().insert(dataUri,nameVaues);
//6.先更新phone的数据
ContentValues phonoeVaues = new ContentValues();
phonoeVaues.put("data1",phone); //把name数据更新到data1列
phonoeVaues.put("raw_contact_id",contact_id); //告诉系统新插入的name属于哪个联系人
phonoeVaues.put("mimetype","vnd.android.cursor.item/phone_v2");
//7.phone 更新到data表
getContentResolver().insert(dataUri,phonoeVaues);
//8.先更新phone的数据
ContentValues emailVaues = new ContentValues();
emailVaues.put("data1",email); //把name数据更新到data1列
emailVaues.put("raw_contact_id",contact_id); //告诉系统新插入的name属于哪个联系人
emailVaues.put("mimetype","vnd.android.cursor.item/email_v2");
//9.phone 更新到data表
getContentResolver().insert(dataUri,emailVaues);
-
}
7.内容观察者
内容观察者不是四大组件. 可以用来观察数据库是否被操作了
注册内容观察者代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uri uri = Uri.parse("content://com.itheima/");
//1.注册一个内容观察者 参数2:fase 必须是一个精确uri
getContentResolver().registerContentObserver(uri,true,new MyContentObserver(new Handler()));
}
//定义内容观察者
class MyContentObserver extends ContentObserver{
public MyContentObserver(Handler handler) {
super(handler);
}
//当我们观察的内容发生了改变就会执行这个方法
@Override
public void onChange(boolean selfChange) {
System.out.println("哈哈 我执行了");
super.onChange(selfChange);
}
}
}
8.今天总结
1.内容提供者工作原理 掌握
☆
☆
☆
2.内容提供者实现步骤 掌握 ☆
☆
☆
3.短信备份案例
☆
☆
☆
4.虚假短信
☆
☆
☆
5.查询联系人
☆
☆
☆
6.插入联系人
☆
☆
☆
7.内容观察者
☆