安卓开发_深入理解Content Provider
一、Content Provider概述
Content Provider用于保存和获取数据,并使其对所有应用程序可见,这是不同应用程序之间共享数据的唯一方式,因为在Android中没有提供所有应用可以共同访问的公共存储区域
1、 Content Provider内部的数据如何保存是由其设计者决定的,而所有的的Content Provider都实现一组通用的方法,用来提供数据的增删改查操作
2、 客户端如果要使用这些操作方法,可以通过ContentProvider对象实现对 Content Provider的操作,而开发人员可以通过调用getContentResolver()方法来获得ContentProvider对象
即:ContentResolver cr = getContentProvider();
3、 不同进程之间的通信由ContentResolver类和ContentProvider类处理
二、Content Provider提供数据的数据模型
_ID |
NAME |
AGE |
001 |
Alice |
17 |
002 |
Mark |
20 |
003 |
Tom |
11 |
可以看出使用的是基于数据库模型的简单表格来提供其中的数据 行:记录 列:字段
*每条记录都包含一个_ID字段,用于在表中唯一标识该记录
ID字段前包含一个下划线_ ,这是必须有的,不能不写
三、URI
1、 每个Content Provider提供公共的URI(使用URI类包装)来唯一标识其数据集
2、 URI常量用于所有与Content Provider的交互,每个Content Provider方法都是用URI作为方法的第一个参数,这个参数(URI)用来标识ContentResolver应该使用Content Provider中的哪一个数据表
3、 URI: content://com.xqx.mycontent/dba/010
(1)content:// :标准的前缀,用于标识该数据由Content Provider管理,固定值,不用修改
(2)com.xqx.mycontent :URI的authority部分,用于标识Content Provider,在清单文件的<provider>元素的authority属性中声明该authority ,对于第三方应用,该部分为完整的类名(全部小写字母)
(3)/dba :路径部分,用于决定哪类数据被请求,如果Content Provider只提供一种数据类型,则可省略该部分、如果提供多种类型,则由多部分组成
(4)/010 :被请求的特定记录的ID ,如果请求的记录不限于单条记录(比如查询全部字段),该部分不用写
四、预定义Content Provider
1、 安卓系统提供了很多预定义的Content Provider(声音,联系人,通话记录等)
Eg:
Browser :读取或修改书签,浏览历史或网络搜索
CallLog :查看或更新通话记录
Contacts: :获取修改或保存联系人信息
MediaStore:访问图片视频音乐等
2、 查询数据
如果想查询Content Provider数据,必须需要三个信息
(1) 标识该Content Provider的URI
(2) 需要查询的数据字段的名称
(3) 字段值数据的类型
*如果查询特定的记录,则还需要提供该记录的ID值
为了限制返回一条数据,可以在URI结尾添加要操作记录的ID,
Content://…./003
实现该功能可以使用静态方法ContentUris.withAppendedId(),返回值为一个增加了ID的URI对象
获得数据用Cursor对象处理,它能向前或向后遍历整个查询结果集。
3、 增加记录
(1) 向ContentProvider中添加数据,需要使用ContentValues对象建立键值对映射,键位Content Provider中的字段,值为要添加的值
(2) 调用ContentResolver.insert(URI,value);
第一个参数为要操作的ContentProvider唯一标识的URI,第二个参数为ContentValues映射 ,该方法返回添加记录的完整的URI
4、 删除记录
(1)需要调用int delete (Uri url, String where, String[] selectionArgs)方法 ,第一个为要操作的URI ,第二个为删除的条件,第三个参数为填充值
int delete (Uri url, “_id=?”, 11) 为删除URI 中id为11的记录
五、 自定义Content Provider
1、 我们从上面了解了开发人员可以使用系统给定的ContentProvide
当然我们也可以自定义ContentProvider来共享自己的数据(当然也可以使用系统预定义的ContentProvider,管理相同的数据并且有写入权限,也可修改对应数据)
自定义ContentProvider步骤
(1)、建立数据存储系统
Android提供了SQLiteOpenHelper 类帮助创建数据库,SQLiteDatabase类帮助管理数据库
(2)、继承ContentProvider
需要重写6个抽象方法
方法 |
说明 |
|
用于初始化provider |
query() |
返回数据给调用者 |
insert() |
插入新数据到ContentProvider |
updata() |
更新数据 |
delete() |
从ContentProvider中删除数据 |
getType() |
返回CntentProvider数据的MIME类型 |
eg:
package com.example.mycontentprovider; import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; public class DBhelper extends SQLiteOpenHelper{
public DBhelper(Context context) {
super(context, "users.db", null, );
} @Override
public void onCreate(SQLiteDatabase db) {
// TODO 初始化数据库
db.execSQL("create table t_user(_id integer primary key,uname,upass,money)"); db.execSQL("create table t_order(_id integer primary key,user_id,price,productname)"); db.execSQL("insert into t_user(uname,upass,money) values('lisi','123',200)"); db.execSQL("insert into t_user(uname,upass,money) values('zhangsi','1234',2000)"); } @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO 数据库升级时执行该方法
if(newVersion>oldVersion)
{
db.execSQL("drop table if exists t_user");
db.execSQL("drop table if exists t_order"); onCreate(db);
} } }
DBhelper类 继承SQLiteOpenHelper
package com.example.mycontentprovider; import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri; public class UserContentProvider extends ContentProvider{
/*
* 这里有两个数据表t_user t_order
* 给t_user Code标识1
* 给t_order Code标识2
* 假设当前只对表t_user操作
*
*/ //声明该ContentProvider的唯一标识
public static final String AUTHORITY="com.xqx_mydatabase";
//为该组件中可以被外界访问 数据库中的资源定义Code标识
public static final int CODE_USER = ;
public static final int CODE_ORDER = ;
//定义访问资源的URI匹配器,使用该类生成被访问的资源的URI
private static UriMatcher uriMather;
private DBhelper dbhelper;
static {
uriMather = new UriMatcher(UriMatcher.NO_MATCH);
//CODE_USER(1)对应的URI:content://com.xqx_mydatabase/user
uriMather.addURI(AUTHORITY, "user", CODE_USER);
//CODE_USER(2)对应的URI:content://com.xqx_mydatabase/order
uriMather.addURI(AUTHORITY, "order", CODE_ORDER);
} //删除返回删除成功记录的条数
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbhelper.getWritableDatabase();
if(uriMather.match(uri)==CODE_USER)
{
//删除t_user表中的数据,返回删除记录的条数
int num = db.delete("t_user", selection, selectionArgs);
return num;
}
return ;
} @Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
} //插入记录
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbhelper.getWritableDatabase();
if(uriMather.match(uri)==CODE_USER)
{
//得到插入记录的ID
long id = db.insert("t_user", null, values);
//返回新插入记录的URI
return ContentUris.withAppendedId(uri, id);
}
return null;
} //创建DBhelper对象
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
dbhelper = new DBhelper(getContext());
return false;
} //查询,返回Cursor对象
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbhelper.getReadableDatabase();
//得到uri对应的Code
int code = uriMather.match(uri);
Cursor cursor = null;
switch (code) {
//如果匹配CODE_USER 操作数据表t_user
case CODE_USER:
//查询数据表t_user
cursor = db.query("t_user", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CODE_ORDER:
break;
default:
break;
} return cursor;
} //修改数据表中的数据,返回修改记录的条数
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db = dbhelper.getWritableDatabase();
if(uriMather.match(uri)==CODE_USER)
{
return db.update("t_user", values, selection, selectionArgs);
} return ;
} }
UserContentProvider.class 继承ContentProvider
(3)、在应用程序的AndroidManifest文件中注册Content Provider
<!-- 注册 ContentProvider组件
android:authorities:声明该组件的唯一标识
android:permission:声明该组件的权限
android:exported="true":声明该组件可以被外界应用访问
-->
<provider
android:name="com.xqx.UserContentProvider"
android:authorities="com.xqx.users"
android:permission="com.xqx.READ_WRITE"
android:exported="true"
/>
-----------------------------------------------------------------------------------------------
安卓开发_深入理解Content Provider的更多相关文章
- 安卓开发_深入理解Handler消息传递机制
一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存 ...
- 安卓开发_深入理解Activity和Fragment的关系
Fragment(碎片)是必须嵌入在 Activity(活动) 中使用的.Fragment的生命周期随着Activity的生命周期的变化而变化 一.首先让我们看下Activity和Fragment的生 ...
- 安卓开发_浅谈ListView(SimpleAdapter数组适配器)
安卓开发_浅谈ListView(ArrayAdapter数组适配器) 学习使用ListView组件和SimapleAdapter适配器实现一个带图标的ListView列表 总共3部分 一.MainAc ...
- 安卓开发_数据存储技术_sqlite
一.SQLite SQLite第一个Alpha版本诞生于2000年5月,它是一款轻量级数据库,它的设计目标是嵌入式的,占用资源非常的低,只需要几百K的内存就够了.SQLite已经被多种软件和产品使用 ...
- 安卓开发_浅谈ListView(自定义适配器)
ListView作为一个实际开发中使用率非常高的视图,一般的系统自带的适配器都无法满足开发中的需求,这时候就需要开发人员来自定义适配器使得ListView能够有一个不错的显示效果 有这样一个Demo ...
- 安卓开发_数据存储技术_SharedPreferences类
SharedPreferences类 供开发人员保存和获取基本数据类型的键值对. 该类主要用于基本类型,例如:booleans,ints,longs,strings.在应用程序结束后,数据仍旧会保存. ...
- 安卓开发_深入学习ViewPager控件
一.概述 ViewPager是android扩展包v4包(android.support.v4.view.ViewPager)中的类,这个类可以让用户左右切换当前的view. ViewPager特点: ...
- 安卓开发_浅谈Android动画(四)
Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1. ValueAnimator 基本属 ...
- 安卓开发_浅谈Fragment之ListFragment
ListFragment,即Fragment的一个子类,当我们用的一个Fragment只需要一个listview视图的时候使用 该类有几个特点: 1.ListFragment 本身具只有一个ListV ...
随机推荐
- 《机器学习实战(基于scikit-learn和TensorFlow)》第五章内容学习心得
本章在讲支持向量机(Support Vector Machine). 支持向量机,一个功能强大的机器学习模型,能够执行线性或非线性数据的分类.回归甚至异常值检测的任务.它适用于中小型数据集的分类. 线 ...
- javascript History对象属性和方法
History对象 History对象包含用户(在浏览器窗口中)访问过的URL length: 返回浏览器历史列表中的URL数量(打开浏览器,访问淘宝,返回1,再访问百度,返回2) History对象 ...
- linux中sed命令的使用
sed命令是linux或者shell编程中常用的筛选.替换命令,如果能熟练使用sed则对经常使用的人来说在工作上是非常有帮助的 下面把sed主要的用法列出来(有错误的地方大家可以指正): p命令只打印 ...
- 用DDD模拟案例分析
之前我写了几篇关于DDD的介绍和一些小例子说明,我想这对于介绍DDD还是有些模糊,甚至还不知道怎么用DDD来分析设计.昨天和园友讨论也发现没有例子很难说明,所以今天我模拟了一个案例,同时这个案例也是真 ...
- 强制清除 gradle 依赖缓存
今天同事误上传一个库,然后又删除了... 我刚好把他上传的库给down下来了...然后项目一直报错,clean...重新编译...删build文件....全都不管用===== 好几个人研究了好久,只能 ...
- Android应用系列:双击返回键退出程序
前言 有一个很古老的应用技巧,一直被各种大大小小的app用得乐此不疲,那就是双击返回键退出程序.今天就写写它的实现代码,非常简单而且实用. 正文 双击返回键退出程序,一般有两种实现思路,一种是用一个布 ...
- PHP-CPP开发扩展(六)
PHP-CPP是一个用于开发PHP扩展的C++库.本节讲解在C++中PHP异常.变量.常量的实现相关知识. 异常 PHP和C++都支持异常,而PHP-CPP库这两种语言之间的异常处理是完全透明的.你在 ...
- rhel 配置centos源
1.删除自带的yum包,清除/etc/yum.repos.d下面的文件 rpm -qa|grep yum|xargs rpm -e --nodeps(不检查依赖,直接删除rpm包) 2.安装cento ...
- EOS多节点组网:商业场景分析以及节点启动时序
区块链公链都是基于p2p网络,本篇文章将建立一个多节点不同职责参与的EOS的测试网络,根据路上发现的可做文章的技术点大做文章. 关键字:EOS组网,全节点,交易确认,boot sequence,sta ...
- win32编程简介
win32编程简介 复习Win32整理下知识. 为什么学习win32? 我们要编写windos程序.都离不开API. 也就是我们所说的win32程序. 所以学好win32是你能不能再windows下编 ...