用途
Android ContentResolver 是一个系统服务,用于访问和操作其他应用程序提供的数据。它提供了一种统一的接口,允许应用程序在不直接相互依赖的情况下共享数据。
ContentResolver 的用途包括:
- 访问系统数据库,例如联系人、通话记录和短信。
- 访问其他应用程序提供的自定义数据。
- 在应用程序之间共享数据。
ContentResolver 的工作原理是使用 ContentProvider。ContentProvider 是一个特殊的应用程序组件,用于提供对数据的访问。ContentProvider 必须提供以下方法:
- query():查询数据。
- insert():插入数据。
- update():更新数据。
- delete():删除数据。
ContentResolver 使用 URI 来标识要访问的数据。URI 是一个统一资源标识符,它指定了数据的资源位置。例如,以下 URI 表示联系人数据库:
content://com.android.contacts/contacts
要使用 ContentResolver 访问数据,应用程序必须先获取 ContentResolver 对象。可以通过以下方法获取 ContentResolver 对象:
Context context = getApplicationContext();
ContentResolver contentResolver = context.getContentResolver();
获取 ContentResolver 对象后,应用程序可以使用它来查询、插入、更新和删除数据。例如,以下代码查询联系人数据库:
Cursor cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null
);
cursor 对象包含查询结果。应用程序可以使用 cursor 对象来遍历查询结果并获取每个联系人的数据。
ContentResolver 是 Android 开发中一个非常重要的工具。它允许应用程序在不直接相互依赖的情况下共享数据。这使得应用程序开发更加灵活和模块化。
以下是一些使用 ContentResolver 的示例:
- 应用程序可以使用 ContentResolver 访问系统设置。
- 应用程序可以使用 ContentResolver 访问媒体库。
- 应用程序可以使用 ContentResolver 访问其他应用程序提供的自定义数据。
方法
ContentResolver 提供以下方法:
- query():查询数据。
- insert():插入数据。
- update():更新数据。
- delete():删除数据。
- notifyChange():通知 ContentResolver 数据已更改。
- registerContentObserver():注册 ContentObserver 以监听数据更改。
- unregisterContentObserver():取消注册 ContentObserver。
以下是这些方法的详细说明:
query()
query() 方法用于查询数据。它接受以下参数:
- uri:要查询的 URI。
- projection:要返回的列。
- selection:要查询的行。
- selectionArgs:selection 参数中的占位符值。
- sortOrder:排序顺序。
query() 方法返回一个 Cursor 对象,其中包含查询结果。应用程序可以使用 Cursor 对象来遍历查询结果并获取每个联系人的数据。
insert()
insert() 方法用于插入数据。它接受以下参数:
- uri:要插入数据的 URI。
- values:要插入的数据。
insert() 方法返回一个 Uri 对象,该对象标识插入的数据。
update()
update() 方法用于更新数据。它接受以下参数:
- uri:要更新数据的 URI。
- values:要更新的数据。
- selection:要更新的行。
- selectionArgs:selection 参数中的占位符值。
update() 方法返回一个 int 值,该值指示更新的行数。
delete()
delete() 方法用于删除数据。它接受以下参数:
- uri:要删除数据的 URI。
- selection:要删除的行。
- selectionArgs:selection 参数中的占位符值。
delete() 方法返回一个 int 值,该值指示删除的行数。
notifyChange()
notifyChange() 方法用于通知 ContentResolver 数据已更改。它接受以下参数:
- uri:已更改数据的 URI。
- observer:要通知的 ContentObserver。
registerContentObserver()
registerContentObserver() 方法用于注册 ContentObserver 以监听数据更改。它接受以下参数:
- uri:要监听的 URI。
- observer:要注册的 ContentObserver。
unregisterContentObserver()
unregisterContentObserver() 方法用于取消注册 ContentObserver。它接受以下参数:
- observer:要取消注册的 ContentObserver。
例
1. 查询数据
// 查询所有联系人
Cursor cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null
);
// 遍历查询结果
while (cursor.moveToNext()) {
// 获取联系人的姓名
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
// 获取联系人的电话号码
String phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.PHONE_NUMBER));
// ...
}
cursor.close();
2. 插入数据
// 插入一条联系人
ContentValues values = new ContentValues();
values.put(ContactsContract.Contacts.DISPLAY_NAME, "John Doe");
values.put(ContactsContract.Contacts.PHONE_NUMBER, "123-456-7890");
Uri uri = contentResolver.insert(ContactsContract.Contacts.CONTENT_URI, values);
3. 更新数据
// 更新联系人的姓名
ContentValues values = new ContentValues();
values.put(ContactsContract.Contacts.DISPLAY_NAME, "Jane Doe");
int count = contentResolver.update(
ContactsContract.Contacts.CONTENT_URI,
values,
ContactsContract.Contacts._ID + " = ?",
new String[] {"1"}
);
4. 删除数据
// 删除一条联系人
int count = contentResolver.delete(
ContactsContract.Contacts.CONTENT_URI,
ContactsContract.Contacts._ID + " = ?",
new String[] {"1"}
);
5. 监听数据更改
// 注册 ContentObserver 监听联系人数据更改
ContentObserver observer = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
// 当联系人数据更改时,执行此方法
}
};
contentResolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, observer);
// 取消注册 ContentObserver
contentResolver.unregisterContentObserver(observer);
也可以写成同步
ContentResolver.registerContentObserver()方法除了常用的异步方法之外,还提供了一些同步方法,用于阻塞当前线程,直到观察到的Uri发生变化。这些同步方法包括:
- registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer)
- registerContentObserver(Uri uri, boolean notifyForDescendants, int flags, ContentObserver observer)
这两个方法的第一个参数是Uri,用于指定要观察的Uri。第二个参数是boolean类型,用于指定是否通知子Uri的变化。第三个参数是ContentObserver,用于接收数据更改通知。
**registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer)**方法的第四个参数是flags,用于指定注册ContentObserver的标志。该标志可以是以下值:
- ContentObserver.FLAG_SINGLE_URI: 仅观察指定的Uri,不观察子Uri。
- ContentObserver.FLAG_NOTIFY_FOR_DESCENDANTS: 观察指定的Uri及其所有子Uri。
**registerContentObserver(Uri uri, boolean notifyForDescendants, int flags, ContentObserver observer)**方法的同步方法会阻塞当前线程,直到观察到的Uri发生变化。当Uri发生变化时,ContentObserver的onChange()方法会被调用。
以下是一个使用registerContentObserver()方法同步方法的示例:
// 注册 ContentObserver 监听联系人数据更改
ContentObserver observer = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
// 当联系人数据更改时,执行此方法
}
};
contentResolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, ContentObserver.FLAG_NOTIFY_FOR_DESCENDANTS, observer);
// 等待联系人数据更改
synchronized (observer) {
observer.wait();
}
// 取消注册 ContentObserver
contentResolver.unregisterContentObserver(observer);
在这个示例中,我们使用registerContentObserver()方法的同步方法注册了一个ContentObserver,用于监听联系人数据更改。然后,我们使用synchronized关键字锁住observer对象,并调用wait()方法阻塞当前线程。当联系人数据发生变化时,ContentObserver的onChange()方法会被调用,并唤醒当前线程。最后,我们使用unregisterContentObserver()方法取消注册ContentObserver。
请注意,使用registerContentObserver()方法的同步方法可能会导致性能问题,因为它们会阻塞当前线程。因此,您应该只在需要立即获取数据更改通知的情况下使用这些方法。
notifyForDescendants
notifyForDescendants 参数用于指定是否通知子 Uri 的更改。
- 如果 notifyForDescendants 为 true,则 ContentResolver 会在指定的 Uri 或其任何子 Uri 发生更改时通知 ContentObserver。
- 如果 notifyForDescendants 为 false,则 ContentResolver 仅在指定的 Uri 发生更改时通知 ContentObserver。
例如,假设您注册了以下 ContentObserver:
contentResolver.registerContentObserver(
ContactsContract.Contacts.CONTENT_URI,
true,
observer
);
如果 notifyForDescendants 为 true,则 ContentObserver 会在以下情况下收到通知:
- 任何联系人 Uri 发生更改,例如插入、更新或删除联系人。
- 任何联系人组 Uri 发生更改,例如插入、更新或删除联系人组。
如果 notifyForDescendants 为 false,则 ContentObserver 仅在以下情况下收到通知:
- 联系人 Uri 发生更改,例如插入、更新或删除联系人。
默认情况下,notifyForDescendants 参数为 false。
以下是一些使用 notifyForDescendants 参数的示例:
- 如果您要监视所有联系人数据的更改,请将 notifyForDescendants 设置为 true。
- 如果您要监视特定联系人的更改,请将 notifyForDescendants 设置为 false。
- 如果您要监视特定联系人组的更改,请将 notifyForDescendants 设置为 false。
请注意,设置 notifyForDescendants 为 true 可能会导致性能问题,因为 ContentResolver 需要跟踪所有子 Uri 的更改。因此,您应该只在需要监视所有子 Uri 的更改的情况下设置 notifyForDescendants 为 true。
监听日历变化代码
public static String CALENDER_URL = "content://com.android.calendar/calendars";
public static String CALENDER_EVENT_URL = "content://com.android.calendar/events";
public static String CALENDER_REMINDER_URL = "content://com.android.calendar/reminders";
class MyHan extends Handler {
@Override
public void dispatchMessage(@NonNull Message msg) {
super.dispatchMessage(msg);
AppLogUtils.i(TAG, "dispatchMessage");
}
}
getContentResolver().registerContentObserver(Uri.parse(CALENDER_REMINDER_URL), true, new ContentObserver(new MyHan()) {
@Override
public boolean deliverSelfNotifications() {
AppLogUtils.i(TAG, "deliverSelfNotifications");
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AppLogUtils.i(TAG, "onChange");
}
@Override
public void onChange(boolean selfChange, @Nullable Uri uri) {
super.onChange(selfChange, uri);
AppLogUtils.i(TAG, "onChange");
}
});
//管理联系人的Uri:
ContactsContract.Contacts.CONTENT_URI
MediaStore.Files.FileColumns.xxx
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
MediaStore.Images.Images.EXTERNAL_CONTENT_URI
MediaStore.Video.Images.EXTERNAL_CONTENT_URI
content://sms/inbox // 收件箱
content://sms/sent //已发送
content://sms/draft //草稿
content://sms/outbox //发件箱(正在发送的信息)
content://sms/failed //发送失败
content://sms/queued //待发送列表 (比如开启飞行模式后,该短信就在待发送列表里)
以下是一些常见的 URI:
- ContactsContract.Contacts.CONTENT_URI: 联系人 Uri。
- ContactsContract.CommonDataKinds.Phone.CONTENT_URI: 电话号码 Uri。
- ContactsContract.CommonDataKinds.Email.CONTENT_URI: 电子邮件地址 Uri。
- CalendarContract.Events.CONTENT_URI: 日历事件 Uri。
- MediaStore.Images.Media.CONTENT_URI: 图像 Uri。
- MediaStore.Audio.Media.CONTENT_URI: 音频 Uri。
- MediaStore.Video.Media.CONTENT_URI: 视频 Uri。
- MediaStore.Files.FileColumns.xxx
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
MediaStore.Images.Images.EXTERNAL_CONTENT_URI
MediaStore.Video.Images.EXTERNAL_CONTENT_URI
您可以使用 ContentResolver 查询这些 Uri 以获取有关数据的更多信息。您还可以使用 ContentResolver 注册 ContentObserver 以监听这些 Uri 的数据更改。
请注意,您需要在应用程序的清单文件中声明所需的权限才能监听系统 URI。例如,要监听联系人数据更改,您需要声明以下权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />
参考地址
目前见过最全的解析:https://blog.csdn.net/carson_ho/article/details/76101093