【Android】安卓四大组件之ContentProvider知识总结

news2024/9/20 16:47:45

文章目录

  • Uri
    • 介绍
    • 组成
  • ContentResolver
    • 用法
    • 获取对象
    • 增删改查
    • 读取联系人
      • 获取权限
      • 配置ListView
  • ContentProvider
    • 方法
    • 步骤
      • 1、注册
      • 2、继承
        • onCreate
        • UriMatcher
        • insert
        • delete
        • update
        • query
        • getType
  • ContentProvider与ContentResolver

Uri

介绍

统一资源标识符(URI)是一种用于标识资源的字符串。它可以是一个网址、文件路径、或其他形式的资源定位符。在Android中,URI通常用于访问内容提供者(Content Provider)提供的数据。

举例:

  1. 获取设备上存储的所有图片

    content://media/internal/images
    
  2. 获取设备上所有联系人信息

    content://contacts/people/
    
  3. 获取ID为45的单个联系人信息

    content://contacts/people/45
    

在Java中,可以通过Uri.parse方法将字符串URI转换为Uri对象。

Uri uri = Uri.parse("content://contacts/people/45");

组成

  1. Scheme
    • 采用前缀 content://,表示这是一个内容提供者的 Uri
    • 例如:content://
  2. Authority
    • 通常采用应用程序的包名,这样可以确保其唯一性。
    • 例如:com.example.provider
  3. Path
    • 指定数据或资源的路径,可以包含具体的表名、资源名以及其他标识符。
    • 例如:/student/1

image-20240730170024367

ContentResolver

ContentResolver 是 Android 框架提供的一个类,用于与内容提供者(Content Provider)交互,提供了一系列增删改查的方法对数据进行操作,这些方法以Uri的形式对外提供数据

image-20240730165724424

用法

ContentResolver为应用程序提供了统一的接口来访问不同的ContentProvider

获取对象

使用getContentResolver()方法获取ContentResolver对象:

ContentResolver contentResolver = getContentResolver();

增删改查

  1. Uri insert(Uri uri, ContentValues values);
    

    插入新数据,并返回新插入数据的URI。

    • ContentValues对象,包含了要插入的数据键值对
  2. int delete(Uri uri, String selection, String[] selectionArgs);
    

    删除匹配条件的数据,并返回删除的行数。

    • selection: SQL WHERE 子句的筛选条件(不包括 WHERE 关键字)。用来确定哪些行会被删除。
    • selectionArgs: 选择条件的参数数组。用于替代selection中占位符(?
  3. int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
    

    更新匹配条件的数据,并返回更新的行数。

  4. Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
    

    查询数据,并返回一个Cursor对象。

    • projection: 指定你要返回的列。如果你想返回所有列,可以传入null
    • sortOrder: 指定排序的方式。

读取联系人

获取通讯录的数据

使用 ContentResolver 来访问系统通讯录中的数据

获取权限

在AndroidMainfest获取权限

<uses-permission android:name="android.permission.READ_CONTACTS" />

配置ListView

在MainActivity中配置ListView

public class MainActivity extends AppCompatActivity {
    // ArrayAdapter用于在ListView中显示联系人列表
    ArrayAdapter<String> adapter;
    // 存储联系人名称和电话号码的列表
    List<String> contactsList = new ArrayList<>();
    // 获取ListView
    private ListView listView;

    // 设置布局,请求权限,初始化ListView和Adapter。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      
        listView = findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contactsList);
        listView.setAdapter(adapter);

        // 检查是否已经获得了读取联系人的权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            // 如果没有,请求该权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
        } else {
            // 如果已经获得,直接读取联系人
            readContacts();
        }
    }

     // 没有权限弹出对话框:如果权限被授予,读取联系人;否则显示提示信息
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // 检查是否是READ_CONTACTS权限的请求结果
        if (requestCode == 1) {
            // 检查权限是否被授予
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 如果被授予,读取联系人
                readContacts();
            } else {
                // 如果未被授予,显示提示信息
                Toast.makeText(this, "联系人权限获取失败", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    // 查询并读取设备上的联系人列表。将查询结果添加到contactsList中,并更新Adapter以显示结果。
    private void readContacts() {
        Cursor cursor = null;
        try {
            // 查询联系人数据
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
            if (cursor != null) {
                // 遍历查询结果
                while (cursor.moveToNext()) {
                    // 获取联系人名称和电话号码的列索引
                    int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
                    int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

                    // 检查列索引是否有效
                    if (nameIndex != -1 && numberIndex != -1) {
                        // 获取联系人名称和电话号码
                        String displayName = cursor.getString(nameIndex);
                        String number = cursor.getString(numberIndex);
                        // 将名称和号码组合后添加到列表
                        contactsList.add(displayName + "\n" + number);
                    }
                }
                // 更新Adapter以显示新的联系人列表
                adapter.notifyDataSetChanged();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭Cursor,释放资源
            if (cursor != null) {
                cursor.close();
            }
        }
    }
}

ContentProvider

内容提供者(Content Provider)是 Android 四大组件之一(Activity、Service、Broadcast Receiver、Content Provider)。它用于在不同的应用之间共享数据,尤其是在进程间通信(IPC)中起着关键作用。内容提供者通过一层中介来控制数据访问,从而确保隐私数据的安全性。

内容提供者本身并不直接存储数据,它只是定义了数据的访问接口。数据的实际存储方式包括文件存储,SharedPreferences 存储,SQLite 数据库存储

方法

创建一个自定义的 ContentProvider 类继承ContentProvider涉及实现一些关键的方法

image-20240730191342740

  1. onCreate() 方法:用于初始化 ContentProvider通常会执行一些初始化操作,比如设置数据库的连接等
  2. getType() 方法:返回给定 Uri 的 MIME 类型,以便系统知道如何处理数据
  3. insert() 方法:用于向 ContentProvider 中插入数据
  4. update() 方法:用于更新 ContentProvider 中的数据
  5. delete() 方法:用于删除 ContentProvider 中的数据
  6. query() 方法:用于查询 ContentProvider 中的数据

步骤

1、注册

创建一个ContentProvider类,as会自动在AndroidManifest.xml中注册

image-20240731210346399

image-20240731210703600

	<provider
            android:name=".MyContentProvider"
            android:authorities="com.example.sqlitedatabasepractice_731"
            android:enabled="true"
            android:exported="true"></provider>

image-20240731201246656

2、继承

继承了ContentProvider,得到了6个要重写的方法

onCreate
	private SQLiteDatabase db;
 	// 初始化
    public boolean onCreate() {
        // 这里是根据自定义的UserDBHelper类的自定义构造方法创建一个UserDBHelper类的对象
        // 然后调用其方法获取SQLiteDatabase类的对象
        UserDBHelper dbHelper = new UserDBHelper(getContext());
        db = dbHelper.getWritableDatabase();
        return true;
    }
UriMatcher

用于根据 URI 来匹配请求,帮助 ContentProvider 解析 URI,并确定应该执行的操作或返回的数据

// UriMatcher用于URI的匹配
private static UriMatcher uriMatcher;
// 静态代码块,初始化 UriMatcher 实例和添加匹配规则
static {
    // 为UriMatcher添加匹配规则
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    // 添加匹配规则,匹配所有以 BASE_PATH 结尾的 URI
    uriMatcher.addURI(AUTHORITY, BASE_PATH, USER_DIR);
    // 添加匹配规则,匹配以 BASE_PATH 结尾,后跟一个 ID 的 URI
    uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", USER_ITEM);
}
insert
public Uri insert(Uri uri, ContentValues values) {
        // 插入一条新记录
        long id = db.insert(UserDBHelper.TABLE_NAME, null, values);
        // 构造新记录的URI并用来返回
        Uri insertedUri = Uri.withAppendedPath(CONTENT_URI, String.valueOf(id));
        return insertedUri;
    }
delete
 public int delete(Uri uri, String selection, String[] selectionArgs) {
        int match = uriMatcher.match(uri);
        int count = 0;

        switch (match) {
            case USER_DIR:
                // 删除满足条件的所有记录
                count = db.delete(UserDBHelper.TABLE_NAME, selection, selectionArgs);
                break;
            case USER_ITEM:
                // 删除指定ID的记录
                String id = uri.getLastPathSegment();
                count = db.delete(UserDBHelper.TABLE_NAME, "id = ?", new String[]{id});
                break;
        }
        return count;
    }
update
 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count = 0;

        switch (uriMatcher.match(uri)) {
            case USER_DIR:
                // 更新满足条件的所有记录
                count = db.update(UserDBHelper.TABLE_NAME, values, selection, selectionArgs);
                break;
            case USER_ITEM:
                // 更新指定ID的记录
                String id = uri.getLastPathSegment();
                count = db.update(UserDBHelper.TABLE_NAME, values, "id = ?", new String[]{id});
                break;
        }

        return count;
    }
query
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Cursor cursor = null;
        switch (uriMatcher.match(uri)) {
            case USER_ITEM:
                // 查询指定ID的记录
                String id = uri.getLastPathSegment();
                cursor = db.query(UserDBHelper.TABLE_NAME, projection, "id = ?", new String[]{id}, null, null, sortOrder);
                break;
            case USER_DIR:
                // 查询所有记录
                cursor = db.query(UserDBHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
                break;
        }
        return cursor;
    }
getType
public String getType(Uri uri) {
        // MINE类型说明
        // 字符串取值,让ANDROID系统知道处理的是整体数据还是单条数据
        // 特点:1.以vnd开头
        // 2.如果Uri以路径形式结尾,后面接android.cursor.dir/,返回的是整个数据表的MIME类型
        //   如果Uri以ID形式结尾,后面接android.cursor.item/,返回的是单个数据项的MIME类型
        // 3.最后接的内容是: vnd.<authority>.<path>
        switch (uriMatcher.match(uri)) {
            case USER_DIR:
                // 返回整个数据表的MIME类型
                return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + BASE_PATH;
            case USER_ITEM:
                // 返回单个数据项的MIME类型
                return "vnd.android.cursor.item/vnd." + AUTHORITY + "." + BASE_PATH;
            default:
                return null;
        }
    }

ContentProvider与ContentResolver

ContentResolver间接调用ContentProvider

ContentProvider操作自己的DataBase数据库

ContentResolver 间接调用 ContentProvider

  • ContentResolver 是用于访问和管理数据的工具,它将操作请求(如 insert(), update(), delete(), query())发送到对应的 ContentProvider
  • ContentResolver 通过 URI 定位到具体的 ContentProvider,并调用其方法来执行实际的数据操作。

ContentProvider 操作自己的数据库

  • ContentProvider 实现了对数据的 CRUD 操作,它会直接与应用程序的数据库进行交互,执行插入、更新、删除和查询等操作。
  • ContentProvider 在这些操作中使用数据库访问对象(如 SQLiteDatabase),并根据 URI 和其他参数来确定需要操作的数据。

比如:

delete() 方法处理删除请求,通过 ContentResolver 转发到具体的 ContentProvider 实现,执行删除操作并返回删除的记录数。

当你在自定义的 ContentProvider 中实现 delete() 方法时,它需要接收来自其他应用程序通过 ContentResolver 传递的删除请求。你需要根据传递的 URI 和选择条件删除数据库中的记录,并返回删除的记录数

ContentProvider` 实现了对数据的 CRUD 操作,它会直接与应用程序的数据库进行交互,执行插入、更新、删除和查询等操作。

  • ContentProvider 在这些操作中使用数据库访问对象(如 SQLiteDatabase),并根据 URI 和其他参数来确定需要操作的数据。

比如:

delete() 方法处理删除请求,通过 ContentResolver 转发到具体的 ContentProvider 实现,执行删除操作并返回删除的记录数。

当你在自定义的 ContentProvider 中实现 delete() 方法时,它需要接收来自其他应用程序通过 ContentResolver 传递的删除请求。你需要根据传递的 URI 和选择条件删除数据库中的记录,并返回删除的记录数



感谢您的阅读
如有错误烦请指正


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nacos服务注册流程

一、客户端自动注册实例流程 1.首先客户端需要引入服务发现包 <groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.2.6.RELEASE</version> 2. NacosServiceRegist…

Linux中,MySQL存储引擎

存储引擎 在数据库中保存的是一张张有着千丝万缕关系的表&#xff0c;所以表设计的好坏&#xff0c;将直接影响着整个数据库。而在设计表的时候&#xff0c;最关注的一个问题是使用什么存储引擎。 MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种都…

【书生大模型实战营第三期 | 入门岛第1关-Linux基础知识】

学习心得&#xff1a;掌握InternStudio开发机与Linux基础 摘要 通过阅读这份详尽的InternStudio开发机与Linux基础教程&#xff0c;我对如何在云端算力平台上进行开发工作有了初步的了解。学习过程中&#xff0c;我不仅掌握了SSH远程连接和端口映射的技巧&#xff0c;还对Lin…

将后台传来的数据,转成easyui-tree所需格式

easyui 中文文档 EasyUI Tree组件需要一个包含特定属性&#xff08;如id, text, children等&#xff09;的JSON对象数组来初始化。 而后台返回的数据&#xff0c;它可能不是我们直接能拿来用的。 方式一&#xff1a;使用loadFilter函数处理来自Web Services的JSON数据。 $(#…

虚拟机处理yum缓存堆积问题

虚拟机处理yum缓存堆积问题 场景&#xff1a;虚拟机用的时间长了&#xff0c;网络不好&#xff0c;yum显示无法安装。此时我们因考虑到Yum软件包管理器的仓库配置文件地方对方太多而导致的问题。 解决方案&#xff1a; 一&#xff1a;首先检查虚拟机设置&#xff1a;确保设备…

东方古全艺藏委八一画展翰墨抒真情,当代艺术家挥笔颂军魂

在2024年这个意义非凡的夏日&#xff0c;随着“八一”建军节的脚步日益临近&#xff0c;一场旨在铭记历史、颂扬英雄、传承精神的书画盛宴——“中国东方文化研究会艺术品收藏交流委员会书画中心”举办的纪念中国人民解放军建军 97 周年书画邀请展&#xff0c;于8月1日在北京饭…

PTA—基础编程题目集(7-19)

7-19 支票面额 目录 题目描述 输入格式&#xff1a; 输出格式&#xff1a; 输入样例1&#xff1a; 输出样例1&#xff1a; 输入样例2&#xff1a; 输出样例2&#xff1a; 参考代码 总结 题目描述 一个采购员去银行兑换一张y元f分的支票&#xff0c;结果出纳员错给了…

Golang内存管理——堆分配

go语言的内存自动分配和回收的&#xff0c;因此内存的使用流程大致为&#xff1a;获取内存——分配内存——回收内存——再分配内存。 其中分配内存分为两方面&#xff0c;堆内存分配和栈内存分配&#xff0c;堆内存和栈内存是两种不同的分配方式&#xff0c;本篇文章主要是堆…

Leetcode刷题——9 基本数据结构(哈希表,并查集)

注&#xff1a;以下代码均为c 1. 哈希表 1.1 重复的DNA序列 什么数据结构既可以保存数据又可以计数&#xff1a;哈希表 vector<string> findRepeatedDnaSequences(string s) {unordered_map<string, int> hash;vector<string> ans;for(int i 0; i 10 &l…

Docker部署RabbitMQ指南

1. Rabbit概述 RabbitMQ是基于Erlang语言开发的开源消息通信中间件&#xff0c;官方地址&#xff1a;https://www.rabbitmq.com/。 2. 单机部署 我们在CentOS7虚拟机中使用Docker来安装。 2.1 下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3-management 方…

Linux 内核源码分析---文件系统关联与字符设备操作

文件系统关联 设备文件都是由标准函数处理&#xff0c;类似于普通文件。设备文件也是通过虚拟文件系统来管理的&#xff0c;和普通文件都是通过完全相同的接口访问。 inode 中设备文件的成员数据 虚拟文件系统每个文件都关联到一个 inode&#xff0c;用于管理文件的属性。 …

RIP、OSPF 协议详解 / Stub/Totally Stub/NSSA/Totally NSSA 区域测试

注&#xff1a;原出处 https://javaforall.cn/204275.html 图片已挂。下文来自 腾讯云 全栈君 RIP、OSPF 协议详解 1、路由协议简介 在互联网中&#xff0c;一个自治系统 (AS) 是一个有权自主地决定在本系统中应采用何种路由协议的小型单位。这个网络单位可以是一个简单的网络…

我们如何提高 Baklib 的 SEO 性能

搜索引擎已经成为我们日常生活中不可或缺的一部分&#xff1b;谷歌甚至成为英语中的动词。因此&#xff0c;每个企业都需要关注其搜索引擎排名。在 Baklib&#xff0c;我们最近遇到了 SEO 排名的挑战。因此&#xff0c;在我们讨论这个问题之前&#xff0c;让我们先了解一下爬行…

宠物空气净化器可以除毛吗?室内浮毛空气净化器推荐

家里养了5只猫&#xff0c;满天飞的猫毛发&#xff0c;随风飘到各个角落&#xff0c;可以说苦不堪言。真的不建议养猫&#xff0c;除非你能接受空气中飞舞着浮毛&#xff0c;衣服、床、筷子、鼻子里全都是猫毛&#xff0c;拉臭臭有异味等等。感觉到处都被猫毛覆盖了&#xff0c…

【多线程】线程状态与并发三大特性的细节剖析

这篇文章主要用于对于多线程的一些查缺补漏。 一、 线程的状态 1&#xff0c;操作系统层面&#xff0c;线程的5种状态 关于线程有几种状态&#xff0c;有多种说法&#xff0c;5、6、7都有。 首先对于操作系统来说&#xff0c;只有5种状态&#xff0c;状态如下新建&#xff…

mac|安装hashcat(压缩包密码p解)

一、安装Macports&#xff08;如果有brew就不用这一步&#xff09; 根据官网文档&#xff1a;The MacPorts Project -- Download & Installation&#xff0c;安装步骤如下 1、下载MacPorts&#xff0c;这里我用的是tar.gz &#xff0c;可以通过keka&#xff08;keka安装在…

《pygame游戏开发实战指南》第三节 理解pygame中的坐标体系

pygame中的坐标体系非常的简单&#xff0c;其实就是一句话&#xff1a;任何对象的左上角都为坐标原点(0, 0)&#xff0c;向右为X轴正方向&#xff0c;向下为Y轴正方向。如下图所示。本节主要通过一些示例来带大家理解这一句话。如果读者已经理解的话&#xff0c;可以直接跳过这…

iPhone不下载APP直接投屏到电脑,这些投影设置你会用吗【电脑投影设置需添加】

最近小编一直在追唐朝诡事录之西行&#xff0c;太好看了&#xff0c;就是手机屏幕有点小&#xff0c;虽然也可以在电脑上看&#xff0c;但是小编心血来潮想投屏到此电脑看看&#xff0c;因此就写了这篇文章。 ①首先打开电脑的设置&#xff0c;打开系统 ②左侧栏中找到投影到此…

学习Java的日子 Day63 文件上传,文件下载,上传头像案例

文件上传下载 1.文件上传 文件上传的应用 比如个人信息的管理&#xff0c;上传头像 比如商品信息的管理&#xff0c;上传商品的图片 这些都需要通过浏览器客户端将图片上传到服务器的磁盘上 2.文件上传原理 所谓的文件上传就是服务器端通过request对象获取输入流&#xff0c;将…

VMware安装Centos虚拟机使用NAT模式无法上网问题处理

NAT模式无法上网问题处理 Centos7与Ubuntu使用同一个NAT网络&#xff0c;Ubuntu正常访问互联网&#xff0c;Centos无法正常访问。 处理方案&#xff1a; cd /etc/sysconfig/network-scripts vi ifcfg-ens33 修改配置项&#xff1a; 重启网络&#xff1a; service network resta…