Android ContentResolver

用途

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

https://www.cnblogs.com/baiqiantao/p/5535471.html

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风徐来辽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值