Android四大组件之ContentProvider

一.定义


- 管理对结构化数据集的访问,封装数据并提供用于定义数据安全性的机制.

- ContentProvider是Android系统中提供的专门用户不同应用间进行数据共享的组件,提供了一套标准的接口用来获取以及操作数据,准许开发者把自己的应用数据根据需求开放给其他应用进行增删改查,而无须担心直接开放数据库权限而带来的安全问题。

二.作用

- 进程间进行数据交互 & 共享,就是跨进程通信.也可以进行进程内通信.

- 跨进程通信示意图

三.原理

底层采用的是Android中的Binder机制

四.具体使用

1.统一资源标识符(URI)

(1)定义

- 标识数据的URI, URI包括整个提供程序的符号名称(授权)和一个指向表的名称(路径).
解释
- 外界进程可以通过URI找到对应的ContentProvider&其表内的数据,然后再进行操作

(2)具体使用

- URI 分为 系统预置 和 自定义两种 , 分别对应系统内置的数据(通讯录,日历等) 和自定义数据库
自定义URI

自定义URI

eg:

Uri uri = Uri.parse("content://com.carson.provider/User/1")

- 标明 URI指向的资源是名为 "com.carson.provider"中ContentProvider中的表名为User,ID为1的数据


//特别注意: URI模式存在匹配通配符 * 和 #

/ *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何内容
	content://com.example.app.provider/* 

// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
	content://com.example.app.provider/table/# 

2.MIME 数据类型

作用

指定某个扩展名的文件用某种应用程序来打开.比如.txt的文件用 text文件打开

(1)ContentProvider 根据 URI 返回MIME的类型

ContentProvider.getType(uri);

(2) MIME 类型组成

每种MIME类型由2个部分组成= 类型+子类型, 就是说
MIME类型是包含了2个部分的字符串

eg:
text/html
application/pdf

(3)MIME类型形式

a.形式1 : 单条记录

	vnd.android.cursor.item/自定义

b.形式2 : 多条记录

	vnd.android.cursor.dir/自定义

//vnd 表示父类型和子类型具有非标准的,特定的形式.
// 父类型已固定好不能更改, 只能区别是单条还是多条记录

3.ContentProvider类

(1) 组织数据方式

ContentProvider 主要以 表格的形式 组织数据,同时也支持文件数据

(2) 主要方法

- 进程间共享数据的本质是: 增删改查数据

- ContentProvider的核心方法也是上述4个作用

eg:

`
<-- 4个核心方法 -->
 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)  
// 外部应用 获取 ContentProvider 中的数据

// 注:
// 1. 上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)
// 2. 存在多线程并发访问,需要实现线程同步
	// a. 若ContentProvider的数据存储方式是使用SQLite & 一个,则不需要,因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
	// b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步

<-- 2个其他方法 -->
public boolean onCreate() 
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作

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

注:

ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver 类

4.ContentResolver类

(1).作用

统一管理不同ContentProvider间的操作
a. 通过URI即可操作不同ContentProvider中的数据
b. 外部进程通过ContentResolver类与ContentProvider进行交互.

(2)为什么不直接只用ContentProvider进行交互,中间还加了一层ContenResolver?###

a. 如果app要和多个ContentProvider进行交互,实现不同的ContentProvider再完成数据交互,操作成本高难度也大.
b. 所以在ContentProvider类上再加上一层ContentResolver类对所有的ContentProvider类进行统一管理.

(3)具体使用

核心方法:

`
// 外部进程向 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)
`

eg:

`
// 使用ContentResolver前,需要先获取ContentResolver
// 可通过在所有继承Context的类中 通过调用getContentResolver()来获得ContentResolver
ContentResolver resolver =  getContentResolver(); 

// 设置ContentProvider的URI
Uri uri = Uri.parse("content://cn.scu.myprovider/user"); 

// 根据URI 操作 ContentProvider中的数据
// 此处是获取ContentProvider中 user表的所有记录 
Cursor cursor = resolver.query(uri, null, null, null,"userid desc"); 

5.ContentUris类

作用

	操作URI

核心方法

	withAppendedId()
	parseId()

eg:

`// withAppendedId()作用:向URI追加一个id
Uri uri = Uri.parse("content://cn.scu.myprovider/user") 
Uri resultUri = ContentUris.withAppendedId(uri, 7);  
// 最终生成后的Uri为:content://cn.scu.myprovider/user/7

// parseId()作用:从URL中获取ID
Uri uri = Uri.parse("content://cn.scu.myprovider/user/7") 
long personid = ContentUris.parseId(uri); 
//获取的结果为:7 
`

6.UriMatcher类

作用

- 在ContentProvider注册 URI
- 根据URI匹配ContentProvider中对应的数据表

eg:

`
// 步骤1:初始化UriMatcher对象
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 
//常量UriMatcher.NO_MATCH  = 不匹配任何路径的返回码
// 即初始化时不匹配任何东西

// 步骤2:在ContentProvider 中注册URI(addURI())
int URI_CODE_a = 1;
int URI_CODE_b = 2;
matcher.addURI("cn.scu.myprovider", "user1", URI_CODE_a); 
matcher.addURI("cn.scu.myprovider", "user2", URI_CODE_b); 
// 若URI资源路径 = content://cn.scu.myprovider/user1 ,则返回注册码URI_CODE_a
// 若URI资源路径 = content://cn.scu.myprovider/user2 ,则返回注册码URI_CODE_b

// 步骤3:根据URI 匹配 URI_CODE,从而匹配ContentProvider中相应的资源(match())

@Override   
public String getType(Uri uri) {   
  Uri uri = Uri.parse(" content://cn.scu.myprovider/user1");   

  switch(matcher.match(uri)){   
 // 根据URI匹配的返回码是URI_CODE_a
 // 即matcher.match(uri) == URI_CODE_a
  case URI_CODE_a:   
    return tableNameUser1;   
    // 如果根据URI匹配的返回码是URI_CODE_a,则返回ContentProvider中的名为tableNameUser1的表
  case URI_CODE_b:   
    return tableNameUser2;
    // 如果根据URI匹配的返回码是URI_CODE_b,则返回ContentProvider中的名为tableNameUser2的表
}   
}

7.ContentObserver类

内容观察者

作用:

观察ContentProvider中的数据变化(增删改) & 通知外界

eg:

`
// 步骤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类进行解除

总结图

### Pandas 文件格式读写操作教程 #### 1. CSV文件的读取与保存 Pandas 提供了 `read_csv` 方法用于从 CSV 文件中加载数据到 DataFrame 中。同样,也可以使用 `to_csv` 将 DataFrame 数据保存为 CSV 文件。 以下是具体的代码示例: ```python import pandas as pd # 读取CSV文件 df = pd.read_csv('file.csv') # 加载本地CSV文件 [^1] # 保存DataFrame为CSV文件 df.to_csv('output.csv', index=False) # 不保存行索引 [^1] ``` --- #### 2. JSON文件的读取与保存 对于JSON格式的数据,Pandas 支持通过 `read_json` 和 `to_json` 进行读取和存储。无论是本地文件还是远程 URL 都支持。 具体实现如下所示: ```python # 读取本地JSON文件 df = pd.read_json('data.json') # 自动解析为DataFrame对象 [^3] # 从URL读取JSON数据 url = 'https://example.com/data.json' df_url = pd.read_json(url) # 直接从网络地址获取数据 # 保存DataFrame为JSON文件 df.to_json('output.json', orient='records') ``` --- #### 3. Excel文件的读取与保存 针对Excel文件操作Pandas 使用 `read_excel` 来读取 `.xls` 或 `.xlsx` 格式的文件,并提供 `to_excel` 方法导出数据至 Excel 表格。 注意:需要安装额外依赖库 `openpyxl` 或 `xlrd` 才能正常运行这些功能。 ```python # 安装必要模块 (如果尚未安装) !pip install openpyxl xlrd # 读取Excel文件 df_excel = pd.read_excel('file.xlsx', sheet_name='Sheet1') # 导出DataFrame为Excel文件 df.to_excel('output.xlsx', sheet_name='Sheet1', index=False) ``` --- #### 4. SQL数据库的交互 当涉及关系型数据库时,Pandas 可借助 SQLAlchemy 库连接各种类型的数据库(如 SQLite, MySQL)。它允许直接查询并将结果作为 DataFrame 返回;或者反过来把现有 DataFrame 插入到指定表中。 下面是基于SQLite的一个例子: ```python from sqlalchemy import create_engine # 创建引擎实例 engine = create_engine('sqlite:///database.db') # 查询SQL语句并返回DataFrame query = "SELECT name, salary, department FROM employees" sql_df = pd.read_sql(query, engine) # 计算各部门平均工资 avg_salary_by_dept = sql_df.groupby('department')['salary'].mean() # 将DataFrame存回SQL表 avg_salary_by_dept.to_sql(name='average_salaries_per_department', con=engine, if_exists='replace', index=True) ``` 上述片段说明了如何执行基本SQL命令以及后续数据分析流程[^4]。 --- #### 5. 多层次索引(MultiIndex)的应用场景 除了常规单维度索引外,在某些复杂情况下可能需要用到多级索引结构。这时可以依靠 MultiIndex 构建更加灵活的数据模型。 例如定义一个多层列名体系: ```python arrays = [['A','A','B','B'], ['foo','bar','foo','bar']] tuples = list(zip(*arrays)) index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second']) df_multi_indexed = pd.DataFrame([[0,1,2,3], [4,5,6,7]], columns=index) print(df_multi_indexed) ``` 这段脚本演示了怎样构建一个具有双重分类标签的表格布局[^2]。 --- ### 总结 综上所述,Pandas 是一种强大而易用的数据处理工具包,适用于多种常见文件类型之间的相互转换及其高级特性应用开发之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值