一、内容提供者的作用
1. 应用成需创建的数据库文件,默认都是私有的,其他应用程序不具备读写权限
2. 如果真的想把自己的数据库数据暴露给其他程序访问,那么就应该通过内容提供者来暴露。
3. 与aidl有点类似,但不太一样,aidl是提供内存中的数据给其他应用访问,内容提供者是提供磁盘中的数据给其他应用访问。
二、使用内容提供者的步骤
1. 自定义一个类,继承ContentProvider
三、学习内容提供者的目的
1. 一般在开发当中都不会把自己的数据暴露出来,也就是编写自定义的内容提供者的几率非常之小。
2. 去访问系统应用暴露出来的数据,如:备份来联系人和备份短信
四、添加和删除短信
* 添加短信
1. Toast
2. Dialog-对话框
3. notification -- 通知
> 通知是运行在另外一个进程中 , systemui
六、联系人的内容提供者
6.1 查询联系人
> 1. 查询raw_contacts表,得到contact_id
> 2. 根据contact_id,去查询 data1, mimetype类型
6.2 删除联系人
> 删除联系人后,发现并不是真的从数据库中把这条记录给移除,而是把contact_id置为null而已,
Android之所以这么做,是为了日后联网同步所考虑的。
6.3 添加联系人
> 先查询raw_contacts表,获取到当前的最新_id
> 内容观察者实际上就是当数据的数据发生了改变之后,发布出来一个通知,如果有哪一个内容观察者
> 在观察这个uri对应的路径,那么就会收到这个通知
* 发布通知
* 注册一个内容观察者
1. 应用成需创建的数据库文件,默认都是私有的,其他应用程序不具备读写权限
2. 如果真的想把自己的数据库数据暴露给其他程序访问,那么就应该通过内容提供者来暴露。
3. 与aidl有点类似,但不太一样,aidl是提供内存中的数据给其他应用访问,内容提供者是提供磁盘中的数据给其他应用访问。
二、使用内容提供者的步骤
1. 自定义一个类,继承ContentProvider
public class Backdoor extends ContentProvider {}
2. 注册,要添加主机名<!-- authorities 它就相当于是一个口令,外部应用如果想操作这个内容提供者,
为他干活,必须要与内容提供者的口令一致才可以。 -->
<provider android:name="com.itheima.db.Backdoor"
android:authorities="com.itheima.db.BANK"></provider>
3. 定义一个Uri匹配器/**
* 由于应用程序一安装,就会把程序中的内容提供者口令发布出来,为了提高数据的安全性, 所以必须对来访的uri(口令),做一些匹配规则过滤一下。
*/
// 定义一个uri的匹配器,指定里面如果传递过来的uri,一旦没有匹配,将返回的int值 -1
static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
4. 预设一些匹配规则 static {
// 一开始就给这个匹配器预设一些匹配规则,如果传递过来的uri
// 匹配了authority 和 path ,那么将返回后面的匹配码
//数据库里面有可能有多张表,为了规范匹配规则,path一般都写表名,根据表的名字来判定
//当前访问的是哪个表的数据 ,如果有多张表,并且还想把这些所有表都暴露出来,那么这个匹配规则
//就应该写多条语句了。并且注意返回的code不能一样。
matcher.addURI("com.itheima.db.BANK", "account", 200);
// matcher.addURI("com.itheima.db.BANK", "stu", 201);
}
5. 编写CRUD方法 @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 使用uri匹配去去过滤传递过来的uri口令,如果匹配成功,将返回200,否则将返回 -1
int code = matcher.match(uri);
if (code == 200) {
System.out.println("delete---");
Db db = new Db(getContext());
SQLiteDatabase data = db.getWritableDatabase();
data.delete("account", selection, selectionArgs);
} else {
throw new IllegalArgumentException("口令错误,滚犊子~~");
}
return 0;
}
6. 在其他应用操作内容提供者 public void insert(View v) {
// 其他应用通过内容提供者 content provider 暴露数据
// 本应用想操作内容提供者---内容解析者
// 1.通过上下文得到内容解析者
ContentResolver resolver = getContentResolver();
// 2. 要访问内容提供者,必须要指定口令
// 由于内容提供者省级了口令,既有主机名也有path路径,所以这里为了能够匹配成功
// 必须加上主机名还有path路径名
Uri uri = Uri.parse("content://com.itheima.db.BANK/account");
//定义要插入的数据
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
values.put("money", 5000);
// 3.调用内容提供者中的添加方法
resolver.insert(uri, values);
}
三、学习内容提供者的目的
1. 一般在开发当中都不会把自己的数据暴露出来,也就是编写自定义的内容提供者的几率非常之小。
2. 去访问系统应用暴露出来的数据,如:备份来联系人和备份短信
四、添加和删除短信
* 添加短信
//添加短信
public void insert(View v) {
ContentResolver resolver = getContentResolver();
//定义口令,这个口令,通过查看上层应用中的provider中的TelephonyProvider 这个应用中清单文件和源代码
Uri uri = Uri.parse("content://sms");
ContentValues values = new ContentValues();
values.put("address", "110");
values.put("date", System.currentTimeMillis());
values.put("type", 1);
values.put("body", "您好,尊敬的覃先生:恭喜您荣获好市民奖,希望您在以后的生活中,勇于和敢于扶老奶奶过马路。");
//操作短信的添加方法
resolver.insert(uri, values);
}
* 删除短信//删除短信
public void delete(View v) {
ContentResolver resolver = getContentResolver();
//定义口令,这个口令,通过查看上层应用中的provider中的TelephonyProvider 这个应用中
//清单文件和源代码
Uri uri = Uri.parse("content://sms");
resolver.delete(uri, "address=?", new String[]{"110"});
Toast.makeText(this, "删除短息成功", 0).show();
}
五、界面提醒1. Toast
2. Dialog-对话框
3. notification -- 通知
> 通知是运行在另外一个进程中 , systemui
//发送通知
public void send(View v){
/*
* 高版本
* //1.得到通知管理者
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//2.定义一个notification的构建器,通过这个构建器去定义通知的一些属性
Notification noti = new Notification.Builder(this)
.setContentTitle("这是标题")
.setContentText("这是文本内容")
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
.build();
//2.发送一个通知 , 指定通知的id,还有通知的对象
manager.notify(1, noti);
*
*
*/
//低版本
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(
R.drawable.ic_launcher, //小图标
"您有一条新的未读消息", // 在状态栏上翻动显示的文本
System.currentTimeMillis()); //短信发送的时间
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel://10086"));
//指定点击通知之后,跳转一个界面
PendingIntent pIntent = PendingIntent.getActivity(
this,
1, //请求码
intent, //跳转的意图
0);//可选的标记
//设置拖动通知下来之后,展示的内容以及点击之后跳转到的界面
notification.setLatestEventInfo(
this,
"这是标题",
"这是文本",
pIntent);
manager.notify(2, notification);
}
六、联系人的内容提供者
6.1 查询联系人
> 1. 查询raw_contacts表,得到contact_id
> 2. 根据contact_id,去查询 data1, mimetype类型
6.2 删除联系人
> 删除联系人后,发现并不是真的从数据库中把这条记录给移除,而是把contact_id置为null而已,
Android之所以这么做,是为了日后联网同步所考虑的。
6.3 添加联系人
> 先查询raw_contacts表,获取到当前的最新_id
//添加一条联系人记录
ContentResolver resolver = getContentResolver();
//2定义查询raw_contact表的uri
Uri contactUri = Uri.parse("content://com.android.contacts/raw_contacts");
//查询data表的uri
Uri dataUri = Uri.parse("content://com.android.contacts/data");****
//由于不知道当前的contact_id已经走到了多少,所以不能盲目直接编写,应该去查询
//该表中的_id列,然后倒序排列,取第一条就可以了。
Cursor cursor = resolver.query(contactUri, new String[]{"_id"}, null, null, "_id desc");
cursor.moveToFirst();
int id = cursor.getInt(0)+1; //在原来的id基础上+1 ,形成了现在新添加的id
> 在它基础上+1 ,得到现在要往数据库添加的新raw_contact_id
ContentValues values = new ContentValues();
values.put("contact_id", id);
resolver.insert(contactUri, values);
> 最后往data表里面添加 姓名、电话、邮箱...
//往data表里面添加数据
//添加姓名
ContentValues nameVal = new ContentValues();
nameVal.put("data1", et_name.getText().toString()); //添加姓名
nameVal.put("raw_contact_id", id); //添加这个数据属于谁的uri
nameVal.put("mimetype", "vnd.android.cursor.item/name"); //指定添加的数据属于什么类型
resolver.insert(dataUri, nameVal);//插入记录
七、内容观察者> 内容观察者实际上就是当数据的数据发生了改变之后,发布出来一个通知,如果有哪一个内容观察者
> 在观察这个uri对应的路径,那么就会收到这个通知
* 发布通知
// 对外发布一个通知,告诉其他人,这个uri对应的数据已经发生了改变。如果第二个参数不是null,
//那么在此指定的这个内容观察者将会收到这个通知,如果是null,代表的是不会直接报告给某一个内容观察者,
//仅仅是发出来一个通知,如果有关心这个通知,那么久能知道事件的发生
getContext().getContentResolver().notifyChange(uri, null);
注意:发布通知这个事件不一定在内容观察者里面执行,也可以在数据库操作完成之后执行。* 注册一个内容观察者
Uri uri = Uri.parse("content://com.itheima.db.BANK/account");
//注册一个内容观察者,让他观察指定的uri, 如果这个uri的数据发生了改变,那么将会得到通知
getContentResolver().registerContentObserver(
uri, //观察指定的uri
true, // 如果是true, 代表只要前面的uri能够匹配成功,那么就会收到通知,如果是false代表的时候
//要所有的路径都完全匹配
new ContentObserver(new Handler()) {
//一旦这个uri对应的数据发生了改变,那么这个方法将会被调用.
@Override
public void onChange(boolean selfChange) {
System.out.println("来人啊,银行行长又来偷钱了。。。");
}
});