icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础内容

  • AndroidCore

    • Activity

    • BroadcastReceiver

    • ContentProvider

      • ContentProvider基础内容
        • 1. ContentProvider简介
          • 1.1 ContentProvider是什么
          • 1.2 ContentProvider执行原理
          • 1.3 ContentProvider相关API
        • 2. ContentResolver 内容提供者解析类
          • 2.1 为什么不直接访问ContentProvider类
          • 2.2 URI 请求地址数据的类
        • 3. 三个辅助ContentProvide的工具类
          • 3.1 UriMatcher-匹配URI的容器
          • 3.2 ContentUris-解析URI的工具类
          • 3.3 ContentObserver类
        • 4. 使用Provider
          • 5.1 进程内通信
        • 5.2 进程内通信
          • 进程 1
          • 进程2
    • Android-Service

    • Intent

  • Android UI

  • Components

  • Fragment

  • 网络操作

  • 异步机制

  • 数据存储

  • 学习笔记

  • 自定义View

  • View事件体系

  • Android
  • AndroidCore
  • ContentProvider
iqqcode
2021-06-02
目录

ContentProvider基础内容

# 1. ContentProvider简介

image-20210414210144862

如短信应用在编辑短信时,需要添加联系人电话,但是联系人列表的表数据存储在库中;当前的联系人数据表是私有的,短信应用无法获取到。此时,我们中间通过ContentProvider(内容提供者)来获取到联系人列表,短信应用通过ContentProvider来获取;短信如何获取ContentProvider暴露的接口呢?通过ContentResolver(内容解析器) 通过 URI 来访问ContentProvider提供的接口

# 1.1 ContentProvider是什么

进程间 进行数据交互 & 共享,即跨进程通信

image-20210416084516252

  • ContentProvider=中间者角色(搬运工),真正存储&操作数据的数据源还是原来存储数据的方式(数据库、文件、xml或网络)
  • 数据源可以:数据库(如Sqlite)、文件、XML、网络等等

ContentProvider是Android四大组件之一,将数据库表数据操作暴露给其他应用访问;其他应用需要使用ContentResolver来调用ContentProvider的方法,通过URI进行通信

ContentProvider是一种数据共享机制,它将允许其它应用程序对自身应用程序中的数据执行增删改查操作;


# 1.2 ContentProvider执行原理

image-20210416101954537


# 1.3 ContentProvider相关API

provider对象创建后调用(应用安装完成或手机启动完成)

public abstract boolean onCreate();
1

查询数据表

public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
1

插入数据表

public abstract Uri insert(Uri uri, ContentValues values);
1

删除数据表

public abstract int delete(Uri uri, String selection, String[] selectionArgs);
1

更新数据表

public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
1

# 2. ContentResolver 内容提供者解析类

统一管理不同 ContentProvider间的操作

  1. 即通过 URI 即可操作 不同的ContentProvider 中的数据
  2. 外部进程通过 ContentResolver类 从而与ContentProvider类进行交互

# 2.1 为什么不直接访问ContentProvider类

为什么要使用通过ContentResolver类从而与ContentProvider类进行交互,而不直接访问ContentProvider类

  • 一般来说,一款应用要使用多个ContentProvider,若需要了解每个ContentProvider的不同实现从而再完成数据交互,操作成本高、难度大
  • 所以再ContentProvider类上加多了一个 ContentResolver类对所有的ContentProvider进行统一管理

得到对象

context.getContentResolver()
1

调用provider进行数据库CRUD操作

insert()
delete()
update()
query()
1
2
3
4

# 2.2 URI 请求地址数据的类

得到URI对象

Uri ststic parse(String uriString)
1

image-20210415081437275

标准URI写法,表示访问top.iqqcode.app这个应用的table表中的数据

content://top.iqqcode.app.provider/table
1

内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以id结尾就表示期望访问该表中拥有相应id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容URI,规则如下。

  • *:表示匹配任意长度的任意字符
  • #:表示匹配任意长度的数字

一个能够匹配任意表的内容URI格式就可以写成:

content://com.example.app.provider/*
1

一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:

content://com.example.app.provider/table1/#
1

# 3. 三个辅助ContentProvide的工具类

# 3.1 UriMatcher-匹配URI的容器

添加合法的URI

void addURI(String anthority, String path, int code)
1

匹配指定的URI,返回匹配码

int match(Uri uri)
1

# 3.2 ContentUris-解析URI的工具类

解析URI,得到字段的id

long parseId(Uri contentUri)
1

添加id到指定的URI中

Uri withAppendedli(Uri contentUri, long id)
1

# 3.3 ContentObserver类

观察 Uri引起 ContentProvider 中的数据变化 & 通知外界(即访问该数据访问者)

当ContentProvider 中的数据发生变化(增、删 & 改)时,就会触发该 ContentObserver类

具体使用

// 步骤1:注册内容观察者ContentObserver
    getContentResolver().registerContentObserver(uri);
    // 通过ContentResolver类进行注册,并指定需要观察的URI

// 步骤2:当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
    public class UserContentProvider extends ContentProvider { 
      public Uri insert(Uri uri, ContentValues values) { 
      db.insert("user", "userid", values); 
      getContext().getContentResolver().notifyChange(uri, null); 
      // 通知访问者
   } 
}

// 步骤3:解除观察者
 getContentResolver().unregisterContentObserver(uri);
// 同样需要通过ContentResolver类进行解除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 4. 使用Provider

40787698

1. 编写Contentprovider子类,继承ContentProvider

<-- 4个核心方法 -->
  // 外部进程向 ContentProvider 中添加数据
  public Uri insert(Uri uri, ContentValues values) 
  
  // 外部进程 删除 ContentProvider 中的数据
  public int delete(Uri uri, String selection, String[] selectionArgs) 
  
  // 外部进程更新 ContentProvider 中的数据
  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
  
 // 外部应用 获取 ContentProvider 中的数据
  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  String sortOrder)  
1
2
3
4
5
6
7
8
9
10
11
12

上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)

存在多线程并发访问,需要实现线程同步

  • a. 若ContentProvider的数据存储方式是使用SQLite,则不需要;因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
  • b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作
public boolean onCreate() 

// 得到数据类型,即返回当前 Url 所代表数据的MIME类型
public String getType(Uri uri)
1
2
3
4
5
6

query方法参数说明

@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    // TODO
}
1
2
3
4
5

【查询参数对照说明】

query()方法参数 对应SQL部分 描述
uri from table_name 指定查询某个应用程序下的某一张表
projection select column1, column2 指定查询的列名
selection where column = value 指定where 的约束条件
selectionArgs - 为where 中的占位符提供具体的值
sortOrder order by column1, column2 指定查询结果的排序方式

SQL语句

selece id,name,age from table where id = ? and name = ? order by ...
1

String[] projection 对应 select 后面查询的字段

String[] selectionArgs 对应 where 后面的条件 id、name等字段放入数组

order by 对应 sortOrder 为排序规则

2. manifest中注册

  • 创建在<application>节点下添加<provider>子节点;
  • 配置android:name属性,指定ContentProvider类;
  • 配置android:authorities属性,指定用于访问数据的URI的host部分;
  • 配置android:exported属性,指定值为true
<provider
    android:name="PersonProvider"
    android:authorities="top.iqqcode.contentproviderbasic.PersonProvider"
    <!-- exported是否可被其他应用访问 -->
    android:exported="true" />
1
2
3
4
5

# 5.1 进程内通信

【步骤说明】

  1. 创建数据库类
  2. 自定义 ContentProvider 类
  3. 注册 创建的 ContentProvider类
  4. 进程内访问 ContentProvider的数据

Demo app02-进程间通信

🎈app-query (opens new window)

🧨app-CRUD (opens new window)

# 5.2 进程内通信

本文需要创建2个进程,即创建两个工程,作用如下

image-20210418154355241

# 进程 1

使用步骤如下:

  1. 创建数据库类
  2. 自定义 ContentProvider 类
  3. 注册创建的 ContentProvider 类

# 进程2

步骤1:声明可访问的权限

编辑 (opens new window)
#ContentProvider
上次更新: 2022/03/27, 22:58:50
BroadcastReceiver基础
Service基础

← BroadcastReceiver基础 Service基础→

最近更新
01
匿名内部类
10-08
02
函数式接口
10-08
03
ARouter-Kotlin踩坑
10-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×