[Android][第一行代码][第 7 章 内容提供器]
2017-09-16 10:43
316 查看
01. 内容提供器简介
跨程序共享数据,内容提供器 Content Provider 主要用于在不同的应用程序之间是实现数据共享功能。它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险。
02. 运行时权限
Android 6.0 以下版本安装时授权,不授权不安装。可在应用管理界面查看权限申请情况。
Android 6.0 及以上版本运行时授权,不授权部分功能不能用。可在应用管理界面管理权限授权或不授权。
权限分类
普通权限
危险权限
特殊权限
每个危险权限都属于一个权限组,申请的某个权限被授权时,该组所有权限也会同时被授权。
请求权限核心方法
ContextCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission)检查是否有权限
ActivityCompat.requestPermissions(Activity activity, String[] permissions, int requestCode)请求权限
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)权限请求结果的回调
/** * 点击按钮执行操作 */ public void request(View view) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {// 判断没有权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);// 请求权限[上下文][权限数组集合][请求码] return; } else {// 判断有权限 callPhone(); } } /** * 请求权限用户操作后回调函数 * * @param requestCode 请求码 * @param permissions 权限数组集合 * @param grantResults 授权情况数组集合 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { callPhone(); } else { ToastUtil.showShortToast(this, "You denied the permission"); } break; } }
03. 访问其他程序的数据
读取系统联系人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()) {// 循环读取数据 String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));// 姓名 String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));// 手机号 } } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close();// 关闭游标 } } }
ContentResolver 的基本用法
通过
Context中的
getContentResolver()方法获取到
ContentResolver的实例。
利用
ContentResolver实例进行数据的
CRUD操作
insert()方法进行
添加数据
update()方法进行
更新数据
delete()方法进行
删除数据
query()方法进行
查询数据
不同于SQLite 的是方法都不接收表名参数,而是使用一个
Uri参数代替。
内容 URI 给内容提供器中的数据建立了唯一标识符,主要由两部分组成:
authority和
path
authority用于对不同的应用程序做区分,采用包名进行命名
path则是用于对同一应用不同表名进行区分,添加在
authority之后
schema协议添加于头部
String uriString = "content://com.just.first/table"; Uri uri = Uri.parse(uriString);
查询数据
Cursor cursor = getContentResolver().query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
查询返回
Cursor对象
query() 方法参数 | 对应 SQL 部分 | 描述 |
---|---|---|
uri | from table_name | 指定查询某应用程序的某张表 |
projection | select column1, column2 | 指定查询的列名 |
selection | where column = value | 指定 where 的约束条件 |
selectionArgs | - | 为 where 中的占位符提供具体的值 |
sortOrder | order by column1, column2 | 指定查询结果的排序方式 |
getContentResolver().insert(Uri url, ContentValues values);
同样使用
ContentValues键值对进行数据的封装
修改数据
getContentResolver().update(Uri uri, ContentValues values, String where, String[] selectionArgs)
删除数据
getContentResolver().delete(Uri uri, ContentValues values, String where, String[] selectionArgs)
04. 创建自己的内容提供器
自定义内容提供器继承ContentProvider
实现 6 个抽象方法
/** * 7.4.1 自定义内容提供器 * * @author JustDo23 */ public class FirstContentProvider extends ContentProvider { /** * 初始化内容提供器。完成数据库的创建和升级操作。[只有当存在 ContentResolver 尝试访问时才会初始化] * * @return [true, 初始化成功][false,初始化失败] */ @Override public boolean onCreate() { return false; } /** * 从内容提供器查询数据。 * * @param uri 指定查询哪张表 * @param projection 确定查询哪些列 * @param selection 约束查询哪些行 * @param selectionArgs 为约束赋值 * @param sortOrder 查询结果排序 * @return 游标对象 */ @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } /** * 向内容提供器中添加数据。 * * @param uri 指定哪张表 * @param values 待添加数据键值对 * @return 返回一个用户表示这条新纪录的 URI */ @Nullable @Override public Uri insert(Uri uri, ContentValues values) { return null; } /** * 更新内容提供器中已有数据。 * * @param uri 指定哪张表 * @param values 待更新数据键值对 * @param selection 约束更新哪些行 * @param selectionArgs 为约束赋值 * @return 返回受影响的行数 */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } /** * 从内容提供器中删除数据。 * * @param uri 指定哪张表 * @param selection 约束删除哪些行 * @param selectionArgs 为约束赋值 * @return 返回被删除的行数 */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } /** * 返回 MIME 类型 * * @param uri 指定哪张表 * @return 返回 MIME 类型 */ @Nullable @Override public String getType(Uri uri) { return null; } }
通配符
一个标准的内容 URI 写法
content://com.just.first/table
表示访问应用
com.just.first中的
table数据表。还可以在其后添加一个
id
content://com.just.first/table/23
表示访问表中
id为
23的数据。
内容 URI的格式主要有以上两种,以路径结尾就表示期望访问该表中的所有数据,以 id 结尾就表示期望访问该表中拥有相应 id 的数据。可以使用通配符来分别匹配这两种格式的内容 URI。
星号表示匹配任意长度的任意字符
井号表示匹配任意长度的数字
一个能够匹配任意表的内容 URI 格式可以写成
content://com.just.first/*
一个能够匹配表中任意一行数据的内容 URI 格式可以写成
content://com.just.first/table/#
通配符使用
public class FirstContentProvider extends ContentProvider { public static final int TABLE_1_DIR = 0;// 自定义码 public static final int TABLE_1_ITEM = 1; public static final int TABLE_2_DIR = 2; public static final int TABLE_2_ITEM = 3; public static UriMatcher uriMatcher;// 用于匹配的对象 public static final String PACKAGE_NAME = "com.just.first";// 主包名 static {// 静态代码块 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 用于匹配的对象 uriMatcher.addURI(PACKAGE_NAME, "table1", TABLE_1_DIR);// 添加路径 uriMatcher.addURI(PACKAGE_NAME, "table1/#", TABLE_1_ITEM);// 可以使用通配符 uriMatcher.addURI(PACKAGE_NAME, "table2", TABLE_2_DIR); uriMatcher.addURI(PACKAGE_NAME, "table2/#", TABLE_2_ITEM); } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch (uriMatcher.match(uri)) {// 进行匹配并返回相应的自定义码 case TABLE_1_DIR: LogUtils.e("查询 table1 表中的所有数据"); break; case TABLE_1_ITEM: LogUtils.e("查询 table1 表中的单条数据"); break; case TABLE_2_DIR: LogUtils.e("查询 table2 表中的所有数据"); break; case TABLE_2_ITEM: LogUtils.e("查询 table2 表中的单条数据"); break; } return null; } }
关于类型
getType()方法是所有内容提供器必须提供的一个方法,用于获取相应的 MIME 类型。
一个内容 URI 所对应的
MIME字符串主要由 3 部分组成
必须以 vnd 开头
如果 URI 以
路径结尾则后接
android.cursor.dir/
如果 URI 以
id结尾则后接
android.cursor.item/
最后接上
vnd.<authority>.<path>
内容 URI
content://com.just.first/table
返回 MIME 类型
vnd.android.cursor.dir/vnd.com.just.first.table
内容 URI
content://com.just.first/table/23
返回 MIME 类型
vnd.android.cursor.item/vnd.com.just.first.table
根据以上内容重写
getType()方法
数据安全问题
因为所有的 CRUD 操作都一定要匹配到相应的内容 URI 格式才能进行,而我们当然不可能向 UriMatcher 中添加隐私数据的 URI,所以这部分数据根本无法被外部程序访问到,安全问题也就不存在了。
05. 实现跨程序数据共享
跨进程访问时不能直接使用 Toast使用内容提供器需要进行注册
<provider android:name=".chapter07.DataBaseProvider" android:authorities="com.just.first.provider" android:enabled="true" android:exported="true" />
06. 进阶 Git
忽略文件项目目录下
.gitignore是忽略文件,允许用户将指定的文件排除在版本控制之外。
查看状态
$ git status
查看修改内容
$ git diff
其后可以指定文件来查看该文件的更改记录
加号代表新增
减号代表删除
撤销未添加的修改
$ git checkout fileName
前提是还没有执行
add命令
撤销未提交的修改
$ git reset HEAD
前提是执行了
add命令但还没有执行
commit命令
查看提交记录
$ git log
提交记录包含
提交 id及
提交人及
提交日期及
提交描述这4个信息
$ git log id -l
命令后为
提交 id及
小写-L查看该 ID 的记录
$ git log id -l -p
查看该 ID 的修改内容
07. 小结
运行时权限内容提供者
相关文章推荐
- Android第一行代码学习笔记五----内容提供器
- 《第一行代码--Android》读书笔记之内容提供器
- android第一行代码-9.内容提供器
- 第一行代码-第7章 内容提供器
- 第一行代码 第7章 内容提供器 --实现跨程序数据共享
- 第一行代码-7.3 创建自己的内容提供器
- Android第一行代码-第二版内容大纲
- 第一行代码 第7章 内容提供器 -- 运行时权限
- 第一行代码-7.1 内容提供器简介
- 第一行代码学习笔记,第七章 内容提供者
- 开源:我的Android新闻客户端,速度快、体积小、支持离线阅读、操作简便、内容展现形式丰富多样、信息量大、功能全面 等(要代码的留下邮箱)
- Android 强制下线功能 第一行代码
- Android为 ContentProvider 提供了那些服务内容?
- 《第一行代码—Android(第二版)》作者郭霖源码-第3章软件也要拼脸蛋
- 第一行代码阅读笔记---详解分析第一个Android程序
- Android组件系列----ContentProvider内容提供者【1】
- Android第一行代码阅读笔记001 主要文件夹介绍、activity的注册、资源引用的方法、Log日志打印的使用
- android_访问系统短信内容提供者
- ANDROID webview加载本地内容代码
- 系出名门Android(9) - 数据库支持(SQLite), 内容提供器(ContentProvider)