为不同的应用之间数据共享提供统一的访问接口,内容提供者的作用 把私有的数据给暴露出来
原理:可以把ContentProvider当成Android系统内部的网站,这个网站以固定的Uri对外提供服务,而ContentResolver则可以当成android系统内部的HttpClient,它可以向指定的Uri发送请求(实际上是调用ContnetResolver的方法),这种请求委托给ContnentProvider处理,从而实现对“网站”内部数据的进行,访问,每一个ContentProvider都拥有一个公共的URI,这个URL用于表示这个ContentProvider所提供的数据
URL : 统一资源定位符 https : //www.baidu.com/
URI : 统一资源标示符 可以自己定义 表示的范围更大些
I / ActivityThread(2895) : Pub com.itheima.db : com.itheima.db.AccountProvider 如果你发现这样一段日志 证明你写的内容提供者没有问题
static {
sURIMatcher.addURI("com.itheima.db", "query", QUERYSUCESS);
}
public class AccountProvider extends ContentProvider {
private static final int QUERYSUCESS = 0; //ctrl + shift + X 表小写加Y
private static final int INSERTSUCESS = 1;
private static final int UPDATESUCESS = 2;
private static final int DELETESUCESS = 3;
//(1)定义urimatcher 路径的匹配器
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private MyOpenHelper myOpenHelper;
//(2)写一个静态代码块 添加匹配规则
static {
/**
* authority 要和你在清单文件里面配置一样
* 比如你访问百度 http://www.baidu.com
* com.itheima.db/query
*
*/
sURIMatcher.addURI("com.itheima.db", "query", QUERYSUCESS);
sURIMatcher.addURI("com.itheima.db", "insert", INSERTSUCESS);
sURIMatcher.addURI("com.itheima.db", "update", UPDATESUCESS);
sURIMatcher.addURI("com.itheima.db", "delete", DELETESUCESS);
}
@ Override
public boolean onCreate() {
//获取类的实例
myOpenHelper = new MyOpenHelper(getContext());
return false;
}
@ Override
public Cursor query(Uri uri, String[]projection, String selection,
String[]selectionArgs, String sortOrder) {
int code = sURIMatcher.match(uri);
if (code == QUERYSUCESS) {
//匹配成功 把curosr返回
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
//我就发条消息 说 数据库被操作了
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 code = sURIMatcher.match(uri);
if (code == INSERTSUCESS) {
//说明路径匹配成功
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
//代表插入到了第几行
long insert = db.insert("info", null, values);
//为了业务严谨一些
if (insert > 0) {
//发送一条通知 说明数据库被操作了
getContext().getContentResolver().notifyChange(uri, null);
}
Uri uri2 = Uri.parse("com.itheima.com" + insert);
db.close();
return uri2;
} else {
//路径匹配失败
//路径匹配失败
throw new IllegalArgumentException("姐们路径不正确 请检测路径...");
}
}
@ Override
public int delete (Uri uri, String selection, String[]selectionArgs) {
int code = sURIMatcher.match(uri);
if (code == DELETESUCESS) {
//说明路径匹配成功
SQLiteDatabase db = myOpenHelper.getReadableDatabase();
//代表影响的行数
int delete = db.delete ("info", selection, selectionArgs);
//发送一条通知 说明数据库内容发生了改变
if (delete > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
db.close();
return delete;
} else {
//路径匹配失败
throw new IllegalArgumentException("姐们路径不正确 请检测路径...");
}
}
@ Override
public int update(Uri uri, ContentValues values, String selection,
String[]selectionArgs) {
int code = sURIMatcher.match(uri);
if (code == UPDATESUCESS) {
//路径匹配成功
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//代表更新的行数
int update = db.update("info", values, selection, selectionArgs);
if (update > 0) {
//发送一条通知 说明数据库内容发生了改变
getContext().getContentResolver().notifyChange(uri, null);
}
db.close();
return update;
} else {
//路径匹配失败
throw new IllegalArgumentException("姐们路径不正确 请检测路径...");
}
}
}
public class MainActivity extends Activity {
@ Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击按钮 增加一条记录
public void click1(View v) {
Uri uri = Uri.parse("content://com.itheima.db/insert"); //小细节
ContentValues values = new ContentValues();
//key :代表列的名字 value:对于的值
values.put("name", "zhaoliu");
values.put("money", "2000000");
Uri uri2 = getContentResolver().insert(uri, values);
System.out.println("uri2:" + uri2);
}
//点击按钮删除一条记录
public void click2(View v) {
Uri uri = Uri.parse("content://com.itheima.db/delete");
int delete = getContentResolver().delete (uri, "name=?", new String[]{
"zhaoliu"
});
Toast.makeText(getApplicationContext(), "删除了" + delete + "行", 1).show();
}
//点击按钮 进行修改
public void click3(View v) {
Uri uri = Uri.parse("content://com.itheima.db/update");
ContentValues values = new ContentValues();
//更新钱数
values.put("money", "2");
int update = getContentResolver().update(uri, values, "name=?", new String[]{
"zhaoliu"
});
Toast.makeText(getApplicationContext(), "更新了" + update + "行", 1).show();
}
//点击按钮 去查询第一个应用里面的数据库的内容
public void click4(View v) {
/**
* path 数据库路径
* factory 游标工厂
*/
/*SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.itheima.db/databases/Account.db", null, SQLiteDatabase.OPEN_READWRITE);
Cursor cursor = db.query("info", null, null, null, null, null, null);
if (cursor!=null && cursor.getCount()>0) {
while(cursor.moveToNext()){
String name = cursor.getString(1);
String money = cursor.getString(2);
System.out.println("第二个应用读取name:"+name+"---"+money);
}
}*/
//(2)第二种查询方法 因为数据库的内容已经通过内容提供者给暴露出来了 所以我们通过内容的解析者去获取
Uri uri = Uri.parse("content://com.itheima.db/query"); //小细节
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String name = cursor.getString(1);
String money = cursor.getString(2);
System.out.println("第二个应用读取name:" + name + "---" + money);
}
cursor.close();
}
}
}
public void click(View v) {
//点击按钮 把一条短信插入到短信数据库
//(1)由于短信的数据库已经通过内容提供者暴露出来了 所以我们可以直接通过内容解析者去操作这个数据库
//(2)直接获取内容解析者 直接通过上下文
Uri uri = Uri.parse("content://sms/");
ContentValues values = new ContentValues();
//address date body一定要和短信数据库表的字段对应
values.put("address", "173815");
values.put("date", System.currentTimeMillis());
values.put("body", "请您马上来一趟 否则后果自负");
//插入一条记录
getContentResolver().insert(uri, values);
}
QQ 微信 陌陌都经常去读取我们手机的联系人
联系人的数据库有三张重要的表
查询联系人的步骤
public class ContactUtils {
// 读取联系人的业务方法
public static List < Contact > readContact(Context context) {
//0创建一个集合用来封装数据
List < Contact > contactLists = new ArrayList < Contact > ();
// 由于联系人的数据库也通过内容提供者把数据暴露出来了 所以我们可以直接通过内容解析者去操作
// (1)先查询rowcontacts表的 contact_id字段 我就可以知道一共有几条联系人
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = context.getContentResolver().query(uri,
new String[]{
"contact_id"
}, null, null, null);
while (cursor.moveToNext()) {
String contact_id = cursor.getString(0); // 拿到contact_id列的内容
System.out.println("contact_id:" + contact_id);
if (contact_id != null) {
//创建Javabean对象
Contact contact = new Contact();
contact.setId(contact_id);
// (2)根据raw_coatct_id 去查询data表 data1 和 mimetypeid
// 2.1 小细节 实际上我们查收data表的时候 查询的不是data表 查询的是view_data的视图 视图就是将多张表进行组合
// view_data这个视图是将data表和mimetyp表进行组合
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);
System.out.println("data1:" + data1 + "----" + mimetype);
// (3)区分一下data1列 具体的数据类型
if ("vnd.android.cursor.item/name".equals(mimetype)) {
System.out.println("姓名:" + data1);
contact.setName(data1);
} else 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)) {
contact.setPhone(data1);
System.out.println("电话号码:" + data1);
}
}
//把Javabean对象加入到集合中
contactLists.add(contact);
}
}
return contactLists;
}
}
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);
//获取我们关心控件
et_name = (EditText)findViewById(R.id.et_name);
et_phone = (EditText)findViewById(R.id.et_phone);
et_email = (EditText)findViewById(R.id.et_email);
}
//点击按钮 把数据插入到联系人数据库
public void click(View v) {
//获取我们关心的数据
String name = et_name.getText().toString().trim();
String phone = et_phone.getText().toString().trim();
String email = et_email.getText().toString().trim();
//TODO 自己判断是是否为空
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
//[0]插入之前先查询一下 一共有多少条记录 (行)
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
int count = cursor.getCount();
int contact_id = count + 1;
//[1]先往rowcontacts 表 插入 一条数据 更新raw_contact_id字段
ContentValues values = new ContentValues();
values.put("contact_id", contact_id);
getContentResolver().insert(uri, values);
//[2]把name 姓名插入到data表
ContentValues nameValues = new ContentValues();
nameValues.put("data1", name); //把数据插入到data1列
nameValues.put("raw_contact_id", contact_id); //新插入的数据属于第几条联系人的
nameValues.put("mimetype", "vnd.android.cursor.item/name"); //告诉数据库插入的name是属于什么数据类型
getContentResolver().insert(dataUri, nameValues);
//[3]把phone 插入到data表中
ContentValues phoneValues = new ContentValues();
phoneValues.put("data1", phone); //把数据插入到data1列
phoneValues.put("raw_contact_id", contact_id); //新插入的数据属于第几条联系人的
phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2"); //告诉数据库插入的name是属于什么数据类型
getContentResolver().insert(dataUri, phoneValues);
//[4]把phone 插入到data表中
ContentValues emailValues = new ContentValues();
emailValues.put("data1", email); //把数据插入到data1列
emailValues.put("raw_contact_id", contact_id); //新插入的数据属于第几条联系人的
emailValues.put("mimetype", "vnd.android.cursor.item/email_v2"); //告诉数据库插入的name是属于什么数据类型
getContentResolver().insert(dataUri, emailValues);
}
}
contentObserver内容观察者 他不是四大组件 不需要在清单文件里面配置
contentProvider内容提供者 是四大组件 需要在清单文件里面配置
getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, new MyContentObserver(new Handler()));
//定义一个内容的观察者
private class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
//当我们关心的数据发生改变的时候调用
@ Override
public void onChange(boolean selfChange) {
System.out.println("哈哈 数据库的内容发生了改变");
super.onChange(selfChange);
}
}