ContentProvider:在Android中实现进程间数据共享

news2024/11/13 13:51:18

目录

一,ContentProvider

二,Uri和UriMatcher工具类

1,Uri

2,UriMatcher

三,自定义ContentProvider

 1,准备数据源

2,创建ContentProvider子类

 3,在Manifest文件中注册ContentProvider

四,使用ContentResolver访问数据

五,获取系统中CP的数据

1,获取通话记录

2,管理多媒体内容


一,ContentProvider

        ContentProvider内容提供者,是一种实现不同应用间共享数据的标准api,当应用想要提供数据时,就提供ContentProvider,其他应用通过ContentResolver来接收数据;

        ContentProvider以Uri的形式对外提供数据,其他应用使用ContentResolver通过Uri来访问数据;

        ContentProvider是单例模式的,多个ContentResolver请求数据时,是委托给同一个CP对象来操作的;

二,Uri和UriMatcher工具类

1,Uri

Uri的结构和网站URL命名规则类似:

Uri举例:content://org.edu.provider/words

  • content://:这部分是Android固定的
  • org.edu.provider:这部分是ContentProvider中的authority,结构一般为包名.provider
  • words:资源部分,根据资源不同这部分不同

通过Uri提供的静态方法parse()来实现将字符串转换为Uri:

  • Uri uri = Uri.parse("content://org.edu.p../words") 

2,UriMatcher

帮助ContentProvider操作Uri,进行Uri判断和注册等功能;

(1)UriMatcher通过构造器构造:

UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//UriMatcher.NO_MATCH 表示不匹配任何路径的返回码(返回-1)

(2)注册Uri,只有注册过的Uri才能被访问:

//Uri的authorities
private static String AUTHORITIES = "com.example.contentprovider.ContentProvider.provider";

//Uri的标识码,用于标识唯一的资源
private static Integer BOOK_CODE = 0;

//注册Uri authorities + 资源名(表名)+ 标识码
matcher.addURI(AUTHORITIES, "tb_books", BOOK_CODE);

//最终Uri格式为"content://com.example.contentprovider.ContentProvider.provider/tb_books/0"

 (3)通过int match(Uri uri)方法来判断Uri的对应的标识符,找不到返回-1:

private String getTable(Uri uri) {
        String tableName = "";
        if(matcher.match(uri) == BOOK_CODE)tableName = "tb_books";
        return tableName;
}

三,自定义ContentProvider

  • 准备数据源:可以是文件存储,Sqlite数据库等数据源;
  • 创建ContentProvider:自定义一个类继承ContentProvider,并重写增删改查等方法;
  • Manifest文件中注册ContentProvider;

 1,准备数据源

(1)以Sqlite数据库为数据源,创建SqliteOpenHelper类:

public class SqliteHelper extends SQLiteOpenHelper {
    public SqliteHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table if not exists tb_books(" +
                "id Integer primary key autoincrement, " +
                "name varchar(20) not null" +
                ");"
        );
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

2,创建ContentProvider子类

(2)创建ContentProvider,重写增删改查等方法,使用UriMatcher注册Uri:

public class MyContentProvider extends ContentProvider {
    private SQLiteDatabase bookDB;

    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

    private static String AUTHORITIES = "com.example.contentprovider.ContentProvider.provider";

    private static Integer BOOK_CODE = 0;

    //注册Uri
    public MyContentProvider() {
        matcher.addURI(AUTHORITIES, "tb_books", BOOK_CODE);
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    private String getTable(Uri uri) {
        String tableName = "";
        if(matcher.match(uri) == BOOK_CODE)tableName = "tb_books";
        return tableName;
    }

    @Override
    public boolean onCreate() {
        //获取Sqlite数据库
        SqliteHelper sqliteHelper = new SqliteHelper(
                getContext(),
                "bookDB.db",
                null,
                1
        );
        bookDB = sqliteHelper.getWritableDatabase();
        //插入数据
        ContentValues contentValuesBooks = new ContentValues();
        contentValuesBooks.put("name", "book1");
        bookDB.insert("tb_books", null, contentValuesBooks);
        return true;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        String table = getTable(uri);
        if(table.isEmpty()){
            return null;
        }else {
            long insert = bookDB.insert(table, null, values);
            if(insert > 0)return uri;
            else return null;
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        String table = getTable(uri);
        if(table.isEmpty()){
            return -1;
        }else {
            int delete = bookDB.delete(table, selection, selectionArgs);
            return delete;
        }
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        String table = getTable(uri);
        if(table.isEmpty()){
            return null;
        }else {
            Cursor cursor = bookDB.query(table, projection, selection, selectionArgs, null, null,sortOrder);
            return cursor;
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        String table = getTable(uri);
        if(table.isEmpty()){
            return -1;
        }else {
            int update = bookDB.update(table, values, selection, selectionArgs);
            return update;
        }
    }
}

 3,在Manifest文件中注册ContentProvider

四,使用ContentResolver访问数据

(1)通过getContentResolver()方法获取ContentResolver对象:

ContentResolver contentResolver = getContentResolver();

(2)获取Uri:

Uri uri = Uri.parse("content://com.example.contentprovider.ContentProvider.provider/tb_books");

 (3)通过ContentResolver调用增删改查等方法:

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding = null;
    private ContentResolver contentResolver;
    private Uri uri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        contentResolver = getContentResolver();
        uri = Uri.parse("content://com.example.contentprovider.ContentProvider.provider/tb_books");

        binding.btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialogUtil.showDialog(
                        MainActivity.this,
                        "添加",
                        "id",
                        "书名",
                        new AlertDialogUtil.DialogClickCallback() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, String input1, String input2) {
                                ContentValues contentValues = new ContentValues();
                                contentValues.put("id", Integer.valueOf(input1));
                                contentValues.put("name", input2);
                                Uri insert = contentResolver.insert(uri, contentValues);
                                if (insert != null) {
                                    Toast.makeText(MainActivity.this, "插入成功", Toast.LENGTH_SHORT).show();
                                } else
                                    Toast.makeText(MainActivity.this, "插入失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                );
            }
        });

        binding.btnDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialogUtil.showDialog(
                        MainActivity.this,
                        "删除",
                        "id",
                        "书名",
                        new AlertDialogUtil.DialogClickCallback() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, String input1, String input2) {
                                String selection = "id = ?";
                                String[] selectionArgs = {input1};
                                int delete = contentResolver.delete(uri, selection, selectionArgs);
                                if(delete > 0){
                                    Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
                                }else
                                    Toast.makeText(MainActivity.this, "删除失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                );
            }
        });

        binding.btnUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialogUtil.showDialog(
                        MainActivity.this,
                        "修改",
                        "id",
                        "书名",
                        new AlertDialogUtil.DialogClickCallback() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, String input1, String input2) {
                                ContentValues contentValues = new ContentValues();
                                contentValues.put("name", input2);
                                String selection = "id = ?";
                                String[] selectionArgs = {input1};
                                int update = contentResolver.update(uri, contentValues, selection, selectionArgs);
                                if(update > 0){
                                    Toast.makeText(MainActivity.this, "修改成功", Toast.LENGTH_SHORT).show();
                                }else
                                    Toast.makeText(MainActivity.this, "修改失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                );
            }
        });

        binding.btnQuery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Cursor cursor = contentResolver.query(uri, null, null, null, null);
                StringBuffer result = new StringBuffer();
                if(cursor == null){
                    Toast.makeText(MainActivity.this, "查询失败", Toast.LENGTH_SHORT).show();
                }else{
                    while(cursor.moveToNext()){
                        int indexOfName = cursor.getColumnIndex("name");
                        int indexOfId = cursor.getColumnIndex("id");
                        int id = cursor.getInt(indexOfId);
                        String name = cursor.getString(indexOfName);
                        result.append("id: " + id + ", name: " + name + "\n");
                    }
                }
                binding.tvResult.setText(result);
            }
        });

    }
}

五,获取系统中CP的数据

        Android系统应用会采用CP(ContentProvider)的形式提供一些开放数据,只要知道相关的Uri。我们就可以直接通过ContentResolver来访问这些数据;

1,获取通话记录

通话记录的Uri为:CallLog.Calls.CONTENT_URI

获取通话记录用到的常量:

  • CallLog.Calls._ID: "_id"
  • CallLog.Calls.CACHED_NAME:”name”
  • CallLog.Calls.NUMBER:”number”
  • CallLog.Calls.TYPE:”type” CallLog.Calls.DATE:”date”
  • CallLog.Calls.DURATION:”duration”

2,管理多媒体内容

此CP支持的Uri如下:

  • MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
  • MediaStore.Audio.Media.INTERNAL_CONTENT_URI
  • MediaStore.Images.Media.EXTERNAL_CONTENT_URI
  • MediaStore.Images.Media.INTERNAL_CONTENT_URI
  • MediaStore.Video.Media.EXTERNAL_CONTENT_URI
  • MediaStore.Video.Media.INTERNAL_CONTENT_URI
  • Content://sms/outbox  发送箱短信URI
  • Content://sms/sent  收信箱短信URI
  • Content://sms/draft  草稿箱短信URI 

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

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

相关文章

100个智能体实战技巧 | 如何让Bot一眼记住你

今天介绍一个智能体实用技巧,让Bot可以一眼认出你并和你主动打招呼。 要实现这个功能,需要用到智能体里的变量 操作步骤 点号开始编辑变量,扣子默认已经有5个变量,不过这些我们暂时用不上这些 点” 新增“,创建一个新…

基于WAMP环境的简单用户登录系统实现(v3版)(持续迭代)

目录 版本说明 实现环境: 流程逻辑框图: 数据库连接 登录页面:login.html 登录处理实现:doLogin.php 用户欢迎页面:welcome.php 密码修改页面:change_password.html 修改处理:doChangePa…

【Python学习-UI界面】PyQt5 小部件1-Label

QLabel 对象可用作显示不可编辑的文本、图像或动态GIF影片的占位符。 它还可以用作其他小部件的助记键。 标签可以显示普通文本、超链接或富文本。 1、普通文本 直接双击输入即可 2、添加超链接 选中对应Label,右键选择多信息文本,添加链接&#xff0c…

全网最详细haproxy配置

Haproxy是法国人Willy Tarreau开发的一款高性能的TCP和HTTP负载均衡器,具有广泛的功能和特性,使其在负载均衡和反向代理领域备受推崇。以下是对Haproxy的详细介绍: 一、基本概述 定义:Haproxy是一个开源的高性能的反向代理或者说…

15个提升学术写作的 ChatGPT 高效技巧

不束手无策地面对空白页面这里有 15 个充满灵感的 ChatGPT 提示,帮助你找到研究灵感、建有力论据、撰写条理清晰的文章,突破创作的障碍,提高学术写作的效率。 学术写作充满挑战。要创作出优秀的文章,必须探索新思维,并…

Python OpenCV 影像处理:边缘检测

►前言 上篇介绍使用OpenCV Python findContours() 函数用于在二值化影像中寻找连通的白色区域,并返回一系列点的集合来表示找到的轮廓。本篇将介绍基于计算影像的梯度,通过在影像中找到梯度值的变化来识别边缘,边缘检测通常用于预处理步骤&…

XXL-JOB分布式定时任务框架快速入门

文章目录 前言定时任务分布式任务调度 1、XXL-JOB介绍1.1 XXL-JOB概述1.2 XXL-JOB特性1.3 整体架构 2、XXL-JOB任务中心环境搭建2.1 XXL-JOB源码下载2.2 IDEA导入xxljob工程2.3 初始化数据库2.4 Docker安装任务管理中心 3、XXL-JOB任务注册测试3.1 引入xxl-job核心依赖3.2 配置…

rust 编译时报错:type annotations needed for Box

如下图所示: 解决方法: 升级time的版本: cargo update -p time

【Python基础】Python入门基础教程(非常详细){附带源码}

引言 Python 是一种广泛使用的高级编程语言,因其简洁的语法和强大的功能库而受到开发者的喜爱。本教程将带你从零开始,逐步掌握 Python 的基础知识,并通过附带的源码和表格来加深理解。 点击免费领取《CSDN大礼包》:Python入门到…

c语言基础知识详解,c语言入门必看

在线书籍:54笨鸟 前言 C 语言是一门抽象的、面向过程的语言,C 语言广泛应用于底层开发,C 语言在计算机体系中占据着不可替代的作用,可以说 C 语言是编程的基础,也就是说,不管你学习任何语言,都…

最详细!教你学习haproxy七层代理

一、工作原理 (1)包括 监听端口:HAProxy 会在指定的端口上监听客户端的请求。 例如,它可以监听常见的 HTTP 和 HTTPS 端口,等待客户端连接。请求接收:当客户端发起请求时,HAProxy 接收到请求。…

Gin框架接入pyroscope完美替代pprof实现检测内存泄露

传统检测内存泄露可以看一下我这篇文章Gin框架接入Prometheus,grafana辅助pprof检测内存泄露-CSDN博客 pyroscope被Grafana收购,GPT来总结一下pyroscope的强大之处🐶 pyroscope github地址 pyroscope与grafana的安装 docker compose安装,这里我们其实…

GET和POST这两种常用的HTTP请求方法的区别

GET和POST是HTTP协议中最常用的两种请求方法,它们在使用场景、安全性、数据传输等方面有很大的不同。让我从以下几个方面来比较GET和POST: 1.「用途和语义」 「GET」: 主要用于获取资源 应该是幂等的,即多次请求应该返回相同的结果 通常用…

超详细!!!electron-vite-vue开发桌面应用之开启调试工具(二)

云风网 云风笔记 云风知识库 上篇已经初步搭建完项目,这次配置比较重要的一部分,那就是开启调试工具,这是开发项目比较重要且基础的部分 vite.config.ts配置更新 main: {// Shortcut of build.lib.entry.entry: electron/main.ts,onstart(ar…

2003-2023年高铁数据高铁开通时间数据

2003-2023年高铁数据高铁开通时间数据 1、时间:2003-2023年 2、来源:整理自高铁航线数据库(Chinese High-speed Rail and Airline Database,CRAD) 3、指标:高铁站名称、开通时间、所在省份、所在城市、所…

通过网关将数据上传到两台eqmx服务器上

我们是通过WAN 来读取数据。 线连接以后打开 然后要配置上去服务器 在这里遇到的问题是我自己搭emqx服务器的时候,没有固定ip地址,这个ip地址要通过ipconfig来获取,然后将其设置为静态IP地址,才可以的。让后emqx服务器还要重新启…

美股开户:新手投资者的完整入门教程

炒美股是许多投资者心中的梦想,但对于新手小白来说,如何开户炒美股可能会显得有些复杂和困难。本文将为您提供一份完整的入门教程,详细介绍从选择券商到完成开户的步骤,帮助您顺利进入美股市场。 选择合适的券商 在开户之前&…

【Linux基础】Linux中的开发工具(1)--yum和vim

目录 ✈️前言一,Linux 软件包管理器 yum1. 什么是软件包2. 如何安装软件3. 如何卸载软件 二,Linux编辑器-vim使用1. vim的基本概念1.1 命令/正常/普通模式1.2 插入模式1.3 底行模式 三,vim命令模式命令集1. 移动光标2. 删除字符3. 复制4. 替…

后端调优——分布式锁选型——入门

文章目录 引言正文分布式锁的定义分布式锁的具体应用场景如何实现分布式锁主动轮询型分布式锁实现思路一、MySQL分布式锁二、Redis分布式锁 监听回调型分布式锁Etcd分布式锁Zookeeper分布式锁 锁的对比 总结 引言 最近面试,一直被问到分布式锁,然后仅仅…

基于Martin实现MapboxGL自定义底图

概述 本文分享基于Martin实现MapboxGL底图的自定义。 实现后效果 Martin简介 Martin 是一个瓦片服务器,它能够从 PostGIS 数据库、PMTiles(本地或远程)以及 [MBTiles] (https://github.com/mapbox/mbtiles-spec) 文件中快速生成并提供矢量瓦…