ContentResolver 内容解析者(解析器)
一、Content
Provider
(内容
提供者
)简介:
(一)、引入:
数据库在Android当中是私有的
,不能将数据库设为WORLD_READABLE,
每个数据库都只能创建它的包访问
。这意味着
只有创建这个数据库的应用程序才可访问它
。也就是说不能跨越进程和包,直接访问别的应用程序的数据库。那么如何在应用程序间交换数据呢?可以使用ContentProvider(内容提供者)来实现。这样就更加安全可靠(想从我家借东西,你不能直接进来拿,要我拿给你).
为什么要暴露数据呢?系统中的电话簿,短信,媒体库等数据,其他app希望访问.
(二)、ContentProvider的功能和意义:
为了在应用程序之间交换数据,Android提供了
ContentProvider
,它是不同应用程序之间进行数据交换的标准API。
当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序可以通过提供ContentProvider来实现;
而其他应用程序需要使用这些数据时,不管提供数据的应用程序是否启动,可以通过
ContentResolver
来操作ContentProvider暴露的数据。包括增加数据insert()、删除数据delete()、修改数据update()、查询数据query()等。
虽然大部分使用ContentProvider操作的数据都来自于数据库,但是也可以来自于文件、SharedPreferences、XML或网络等其他存储方式。
(三)、核心类:
1、
ContentProvider 内容提供者
:(需要暴露数据的A应用程序--类似于服务器端)
可以通过继承一个
ContentProvider
的
抽象类
将自己的数据暴露出去;
A应用通过Uri向外暴露数据。只要将A应用安装到手机上。无论是否运行,其他应用都可以从A应用获取数据。
外界不知道,也无需知道A应用暴露的数据在A应用当中是如何存储的,(是用数据库存储还是用文件存储,还是通过网上获得),外界可以通过一套标准的接口 读取或修改A应用里的数据.
2、
ContentResolver
内容解析者
:(访问操作A应用所暴露的数据--类似于客户端)
外界的程序通过
ContentResolver
可以访问
ContentProvider
提供的数据;
3、 Uri统一资源标识符:
Uri是ContentResolver和ContentProvider进行数据交换的标识。
例如一个Uri是 content://com.qf.day16_contentprovider_t/user/5
Uri
的标准前缀
(协议protocal)
:以“
content://
”作为前缀,表示该数据由
ContentProvider
管理。
Uri
的
authority
部分(授权,权限):"
com.qf.day16_contentprovider_t
"该部分是暴露数据的app的包名。(要求小写)。
Uri
的
path
部分(路径):
"
user
"
用于判断请求的路径(哪些数据被请求)。
被请求的特定记录的
id
值[可选的]: "5" 如果请求不仅限于某个单条数据,该部分及其前面的斜线应该删除。
将一个字符串转换成Uri的方式:
Uri uri = Uri.parse("..............")
【备注:】URI、URL的区别:
首先,URI,是
uniform resource identifier
,统一资源标识符,用来唯一的标识一个资源。
URL是
uniform resource locator
,统一资源定位器,
它是一种具体的URI
,即URL可以用来标识一个资源,而且还指明了如何 定位 这个资源。
也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL则是具体的资源标识的方式。可以认为
URL是一种具体的URI
,它不仅唯一标识资源,而且还提供了定位该资源的信息。URI是一种语义上的抽象概念,可以是绝对的,也可以是相对的,
而URL则必须提供足够的信息来定位,所以,是绝对的。
二、使用
ContentResolver
管理通话记录:
查询手机通话记录,可以利用上下文菜单删除通话记录
整个通话记录列表lv
上下文菜单中的删除项:action_delete
通话记录编号tv_id
对方电话号码tv_number
通话开始时间tv_date
通话类型(呼出/呼入/未接)tv_type
注意需要申请权限,否则运行会出现异常:WRITE_CALL_LOG,READ_CALL_LOG
/**
* ContentProvider内容提供者 1.主要用于不同的应用程序之间,共享数据的。
A:ContentProvider:向外提供数据的
* 用于通过Uri向外暴露数据。只要将应用安装到手机上。无论是否运行,都可以获取数据。
B:ContentResolver:获取并解析数据
* 用于解析通过ContentProvider暴露 出来的数据。 A应用暴露出的是Uri,B应用使用该Uri就可以访问A应用暴露出来的数据了。
* =====================================================
* 本例用于实现通过ContentResovler来获取手机中通话记录
* 通话记录存储在内部存储的系统应用目录中:data/data/com.android.providers.contacts/contacts2.db
* 对外暴露的Uri:"content://call_log/calls"
* step1:通过
getContentResolver
()获取ContentResovler对象
* step2:获取通话记录的Uri:"content://call_log/calls"
* step3:执行查询:ContentResovler对象.query(uri,查询的字段, 条件,条件的参数,排序依据);
* step4:添加权限:
READ_CALL_LOG
读取通话记录,
WRITE_CALL_LOG
写通话记录 通话记录表的核心字段"
_id
",
* "
number
"电话号码, "
date
"时间(毫秒值), "
type
": 1:呼入 2:呼出 3:未接
*/
public class Main3Activity extends AppCompatActivity {
// step2:提供要解析数据对应的Uri,就是电话记录的uri
private Uri uri_callLog = CallLog.Calls.CONTENT_URI;// 系统提供的常量,表示通话记录对外暴露的Uri
// 上面常量的值就是 Uri.parse("content://call_log/calls")得到的结果.
private ContentResolver contentResolver;
private ListView lv_listview;
private MyCursorAdapter adapter;// 自定义的适配器类对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
lv_listview = (ListView) findViewById(R.id.lv_listview);
// step1:获取ContentResolver
contentResolver = getContentResolver();
queryCallLog();// 调用自定义的方法,用于查询并显示通话记录
// 注册 上下文菜单:可以删除某个通话记录
registerForContextMenu(lv_listview);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.call_menu, menu);// 上下文菜单,只有一个"删除"选项
}
// 上下文菜单点击时间处理
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int position = menuInfo.position;// 获得弹出上下文菜单时所选中的条目的位置
Cursor cursor = adapter.getCursor();// 调用CursorAdapter的获取cursor对象的方法
cursor.moveToPosition(position);// 把cursor作为数据源,移动到指定位置
int id = cursor.getInt(cursor.getColumnIndex("_id"));// 通话记录表calls中的字段
switch (item.getItemId()) {
case R.id.action_delete:
// 删除一条记录
int count = deleteCallLog(id);// 调用自定义的删除通话记录的方法
if (count > 0) {
Toast.makeText(Main3Activity.this, "删除成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(Main3Activity.this, "删除失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
queryCallLog();// 调用自定义的重新查询的方法
return super.onContextItemSelected(item);
}
/**
* 删除一条指定的通话记录
*
* @param id
* @return
*/
public int deleteCallLog(int id) {
int count = contentResolver.delete(uri_callLog, "_id=?", new String[]{id + ""});// 也可以第二个参数传"_id="+id,第三参数传null
return count;
}
/**
* 通过contentResolver,查询uri所指向的通话记录数据
* 第一个参数:要操作的应用暴露出的uri。指向通话记录的数据
* 第二个参数:要查询的字段
* 第三个参数:查询的条件
* 第四个参数:条件的参数值
* 第五个参数:排序
*/
// 查询数据
public void queryCallLog() {
// step3:通过contentResolver获取数据
//Uri uri,String[] projection列名数组,String selection查询条件,String[] selectionArgs替换占位符的数组,String sortOrder
Cursor cursor = contentResolver.query(uri_callLog, new String[]{"_id", "number", "date", "type"}, null, null, "date desc");
// SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
// R.layout.item_listview, cursor, new String[] { "_id", "number",
// "date", "type" }, new int[] { R.id.tv_id,
// R.id.tv_number, R.id.tv_date, R.id.tv_type },
// CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//这样填进去日期就只能显示成毫秒数了,不美观
// 因此可以使用继承CursorAdapter的自定义适配器来适配Cursor数据
// 父类CursorAdapter没有无参的构造方法,必须如此传参:
adapter = new MyCursorAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); // 最后一个参数表示,如果数据源发生变化则在后面学习的Loader中可以动态更新.
lv_listview.setAdapter(adapter);
}
// 自定义的继承抽象类CursorAdapter的适配器
class MyCursorAdapter extends CursorAdapter {
// 继承抽象类,重写两个抽象方法
public MyCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);// 父类没有无参的构造方法,必须如此传参
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 指定布局文件,生成一个条目的View对象,注意,在内部类中,上下文是MainActivity.this
return LayoutInflater.from(Main3Activity.this).inflate(R.layout.item_listview, null);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// 填充数据到每个条目的内部组件上,类似于继承BaseAdapter中重写getView()方法
TextView tv_id = (TextView) view.findViewById(R.id.tv_id);
TextView tv_number = (TextView) view.findViewById(R.id.tv_number);
TextView tv_date = (TextView) view.findViewById(R.id.tv_date);
TextView tv_type = (TextView) view.findViewById(R.id.tv_type);
// 从cursor获取数据,显示到textview上
tv_id.setText("" + cursor.getInt(cursor.getColumnIndex("_id")));
tv_number.setText(cursor.getString(cursor.getColumnIndex("number")));
long dateNum = cursor.getLong(cursor.getColumnIndex("date"));// 获取以毫秒表示的date数据
Date date = new Date(dateNum);// 利用毫秒数构建Date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
tv_date.setText(sdf.format(date));
int typeNum = cursor.getInt(cursor.getColumnIndex("type"));
if (typeNum == 1) {
tv_type.setText("呼入");
} else if (typeNum == 2) {
tv_type.setText("呼出");
} else {
tv_type.setText("未接");
}
}
}
}
/**
* 短信息的程序的数据库文件:/data/data/com.android.providers.telephony/mmssms.db
* Uri:content://sms
* step1:获取contentResolver对象
* step2:获取短信息的Uri
* step3:查询,插入
* step4:添加权限:
READ_SMS
,
WRITE_SMS
*
@author
Administrator
* 核心字段:
_id
,
address
电话号码,
body
信息文本,
type
类型(1.接收;2.发送),
date
时间(毫秒)
*/
四、使用
ContentResolver
查询
联系人
:
(一)、 [总结]使用ContentResolver 操作数据的步骤:
1、调用Context的
getContentResolver
()方法获得ContentResolver 对象;
2、调用ContentResolver 的
query()
方法查询数据。
· Cursor
query
(Uri
uri
, String[]
projection
, String where, String[] whereArgs, String sortOrder)
参数解释:
String[]
projection
:表示select语句中需要查询的所有的字段组成的字符串数组。
String where:表示带有
占位符
的where子句组成的字符串;
String[] whereArgs:表示
替换
where参数中
占位符
的数据组成的字符串数组;
String sortOrder:表示select语句中的order by子句组成的字符串;
(二)、
联系人中
管理ContentProvider的几个Uri:
1、联系人的Uri==>
content://com.android.contacts/
raw_contacts
2、电话/邮件地址等数据的Uri==> content://com.android.contacts/
data
数据库位置
:/data/data/com.android.providers.contacts/databases/contacts2.db
用可视化工具打开(例如SQLite Expert)
核心表:
1.raw_contacts原始联系人表
"_id":联系人的id
"display_name":联系人的姓名
2.data数据表
"raw_contact_id":作为外键参照raw_contacts表的_id字段
"data1":具体数据,例如手机号,email,姓名等
"mimetype_id":数据的大类型,例如
1:email; 5:电话; 7:姓名; 在mimetypes表中对应于_id字段
3.mimetypes表
"_id":类型id
"mimetype":具体类型,例如_id为7的mimetype是 vnd.android.cursor.item/name
1 电子邮件
2 即时通讯
3 昵称
4 组织,单位
5 电话号码
6 邮编
7 名字
8 地址
9 身份证识别号
10 头像
11 组群
/**
* 操作手机的联系人: 应用程序数据所在的位置:/data/data/com.android.providers/contacts/contacts2.db
* step1:获取ContentResolver对象
* step2:提供Uri 1、联系人的Uri==>
* content://com.android.contacts/raw_contacts
* 2、电话/邮件地址等数据的Uri==> content://com.android.contacts/data
* step3:执行查询
* step4:
添加权限
: READ_CONTACTS
*
*
@author
Administrator
*/
public class MainActivity extends Activity implements OnClickListener {
private Uri uri_raw_contact = Uri.parse("content://com.android.contacts/raw_contacts");// raw_contacts表
private Uri uri_data = Uri.parse("content://com.android.contacts/data");
private ContentResolver contentResolver;
private ListView lv_listview;
private Button btn_queryData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentResolver = getContentResolver();
initView();// 自定义的获取组件引用和注册监听器的方法
queryContacts();// 自定义的查询联系人的方法
}
public void initView() {
lv_listview = (ListView) findViewById(R.id.lv_listview);
btn_queryData = (Button) findViewById(R.id.btn_queryData);
btn_queryData.setOnClickListener(this);
}
/**
* 获取联系人的信息,并且显示到listview上。 用SimpleAdapter进行适配
*/
public void queryContacts() {
List<Map<String, String>> list = getDataContacts();// 自定义的方法,获取联系人的信息List
// 仅用于展示信息,可以直接使用SimpleAdapter
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item_listview,
new String[] { "_id", "display_name", "phone", "email" },
new int[] { R.id.tv_id, R.id.tv_display_name, R.id.tv_phone, R.id.tv_email });
lv_listview.setAdapter(adapter);
}
// 自定义的用于查询联系人的方法
public List<Map<String, String>> getDataContacts() {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();//初始化结果集
// A:查询raw_contact表,为了得到_id,display_name.
Cursor cursor = contentResolver.query(uri_raw_contact, new String[] { "_id", "display_name" }, null, null,null);
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
String _id = cursor.getString(cursor.getColumnIndex("_id"));
String display_name = cursor.getString(cursor.getColumnIndex("display_name"));
map.put("_id", _id);
map.put("display_name", display_name);
// B:根据查询到_id,查询data表,获取到data1, mimetype字段:
// select data1,mimetype from data where raw_contact_id = _id:
Cursor cursor2 = contentResolver.query(uri_data, new String[] { "data1", "mimetype" }, "raw_contact_id=?",new String[] { _id }, null);
// 存储的是_id对应的联系人的信息:
String email = "";
String phone = "";
String address = "";
while (cursor2.moveToNext()) {
String data = cursor2.getString(cursor2.getColumnIndex("data1"));
String mimetype = cursor2.getString(cursor2.getColumnIndex("mimetype"));// 虽然data表没有这个字段,只有mimetype_id字段,但此处必须这样获取,且获取回来的是一个类似于"vnd.android.cursor.item/email_v2"的字符串
if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
email = email + "|" + data;// 如果mimetype的值为email,表示此处的data中的数据是电子邮箱
} else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {// 电话(有可能有手机的,座机的,家庭的,单位的...)
phone = phone + "|" + data;
} else if ("vnd.android.cursor.item/postal-address_v2".equals(mimetype)) {// 地址
address = address + "|" + data;
}
}
map.put("phone", phone);
map.put("email", email);
map.put("address", address);
list.add(map);//把一个联系人的所有信息存入map后,再将map存入list
}
return list;
}
// 点击按钮,实现查询功能
@Override
public void onClick(View v) {
queryContacts();//调用自定义的方法
}
}
一、自定义ContentProvider:
(一)、操作步骤:
1、自己编写一个类,必须继承自
ContentProvider
类;
2、实现ContentProvider类中所有的抽象方法;
需要实现:
onCreate
() 、
getType()
、
query
() 、
insert
() 、
update
()、
delete
() 等方法。
【备注:】
ContentProvider暴露出来的数据和方法是给其他应用程序来调用。
其他应用程序通过ContentResolver对象调用
query
() 、
insert
() 、
update
()、
delete
() 等。
3、定义ContentProvider的Uri。这个Uri是ContentResolver对象执行CRUD操作时重要的参数;
4、使用UriMatcher对象映射Uri返回代码
;【超纲】
5、在AndroidMainfest.xml文件中使用<provider>标签注册ContentProvider。
(二)、ContentProvider类中的六个抽象方法:
1、boolean
onCreate
()
初始化provider
注意没有ContentResolver试图访问你的Provider之前,它不会创建出来.
2、Uri
insert
(Uri uri, ContentValues values)
插入新数据到ContentProvider
3、int
delete
(Uri uri, String selection, String[] selectionArgs)
从ContentProvider中删除数据
4、int
update
(Uri uri, ContentValues values, String selection, String[] selectionArgs)
更新ContentProvider已经存在的数据
5、Cursor
query
(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
返回数据给调用者
6、String
getType
(Uri uri)
返回ContentProvider数据的MIME类型
(三)、在清单文件中声明注册ContentProvider:
<provider android:name=".WordsContentProvider"
android:authorities
="com.qf.wordscontentprovider"
android:exported
="true"
/>
//
android:name
属性的值:ContentProvider类的子类的完整路径;
//
android:authorities
属性的值:对应于content:URI中的authority部分。
//
android:exported
属性是否允许其他应用调用。如果是false,则该ContentProvider不允许其他应用调用。
【备注:】
ContentProvider是
单例模式
的,当多个应用程序通过使用ContentResolver 来操作使用ContentProvider 提供的数据时,ContentResolver 调用的数据操作会委托给同一个ContentProvider 来处理。这样就能保证数据的一致性。
数据库工具类DBHelper.java
import
android.content.Context;
import
android.database.sqlite.SQLiteDatabase;
import
android.database.sqlite.SQLiteOpenHelper;
public
class
DBHelper
extends
SQLiteOpenHelper
{
public
DBHelper(Context
context
,
int
versionCode
){
super
(
context
,
"users.db"
,
null
,
versionCode
);
}
@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 ,product_name,price,user_id)"
);
//对于
sqlite
来说,只要是integer的主键,则是自动增长的,无需用
autoincrement
指定
db
.
execSQL
(
"insert into t_user(uname,upass,money) values('disen','123',1000)"
);
db
.
execSQL
(
"insert into t_user(uname,upass,money) values('jack','234',10000)"
);
}
@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
);
}
}
}
在AndroidManifest.xml中的<application>标签中:
<!-- 注册ContentProvider组件,
android:
authorities
属性声明当前组件的唯一标识,在Resolver中使用uri时,它作为中间部分,后面还要跟着path
android:exported="true" 设置当前组件可以被外部应用访问 -->
<
provider
android:name
=
"com.user.contentprovider.UserContentProvider"
android:authorities
=
"com.user.contentprovider.users"
android:exported
=
"true"
/>
UserContentProvider.java
public
class
UserContentProvider
extends
ContentProvider {
// 声明当前ContentProvider组件的唯一标识(Authority),注:必须使用小写字母
private
static
final
String
AUTHORITY
=
"com.
user
.contentprovider.users"
;
// 声明访问当前应用下的数据库中哪些资源,给这些访问资源声明code标识
private
static
final
int
CODE_USER
= 0;
private
static
final
int
CODE_ORDER
= 6;
// 声明完整的资源访问
Uri
的匹配器--UriMatcher,实例化它并增加资源访问的
Uri
private
static
UriMatcher
uriMatcher
;
static
{
uriMatcher
=
new
UriMatcher(UriMatcher.
NO_MATCH
);
// 值是-1
//UriMatcher.
addURI
(String authority, String path, int code)
// 用Resolver访问时的
Uri
为
// content://com.qf.contentprovider.users/users
uriMatcher
.addURI(
AUTHORITY
,
"users"
,
CODE_USER
);
// content://com.qf.contentprovider.users/orders
uriMatcher
.addURI(
AUTHORITY
,
"orders"
,
CODE_ORDER
);
//假设是订单表
}
/**
* 自定义的数据库工具类
*/
private
DBHelper
dbHelper
;
@Override
public
boolean
onCreate() {
//
TODO
初始化ConentProvider组件,实例化数据库操作工具类
dbHelper
=
new
DBHelper(
getContext
(), 1);//第二个参数是版本号
return
true
;
// 成功返回true
}
@Override
public
Cursor query(Uri
uri
, String[]
projection
, String
selection
, String[]
selectionArgs
, String
sortOrder
) {
//
TODO
查询数据表
SQLiteDatabase
db
=
dbHelper
.getReadableDatabase();
// 先以读写方式打开数据库,一旦磁盘空间满了,
// 会继续尝试以只读方式打开数据库。
Cursor
cursor
=
null
;
// 查询的结果
// 通过
Uri
匹配器,判断当前请求的
Uri
是访问哪一资源的code
switch
(
uriMatcher
.match(
uri
)) {
case
CODE_USER
:
// 查询t_users用户表的数据:
cursor
=
db
.query(
"t_user"
,
projection
,
selection
,
selectionArgs
,
null
,
null
,
sortOrder
);
break
;
//case CODE_ORDER:.....
}
return
cursor
;
}
@Override
public
Uri insert(Uri
uri
, ContentValues
values
) {
//
TODO
向数据表中插入数据
SQLiteDatabase
db
=
dbHelper
.getReadableDatabase();
// 先以读写方式打开数据库,一旦磁盘空间满了,
// 会继续尝试以只读方式打开数据库。
if
(
uriMatcher
.match(
uri
) ==
CODE_USER
) {//如果是插入t_user表
long
id
=
db
.insert(
"t_user"
,
null
,
values
);
db
.close();
return
ContentUris.
withAppendedId
(
uri
,
id
);
// 将给定的id追加到路径末尾返回
}
//else if()....
return
null
;
}
@Override
public
int
delete(Uri
uri
, String
selection
, String[]
selectionArgs
) {
//
TODO
删除数据表中数据
SQLiteDatabase
db
=
dbHelper
.getReadableDatabase();
if
(
uriMatcher
.match(
uri
) ==
CODE_USER
) {
int
cnt
=
db
.delete(
"t_user"
,
selection
,
selectionArgs
);
db
.close();
return
cnt
;//返回收到影响的行数
}
return
0;
}
@Override
public
int
update(Uri
uri
, ContentValues
values
, String
selection
, String[]
selectionArgs
) {
//
TODO
更新数据表中的数据
SQLiteDatabase
db
=
dbHelper
.getReadableDatabase();
if
(
uriMatcher
.match(
uri
) ==
CODE_USER
) {
int
cnt
=
db
.update(
"t_user"
,
values
,
selection
,
selectionArgs
);
db
.close();
return
cnt
;//返回收到影响的行数
}
return
0;
}
@Override
public
String getType(Uri
uri
) {
//
TODO
Auto-generated method stub
return
null
;
}
}
在另外一个app中利用ContentResolver来使用自定义的ContentProvider暴露出来的数据:
public class MainActivity extends Activity{
private TextView tv_info;
private ContentResolver resolver;
private Uri uri = Uri.parse("content://com.user.contentprovider.users/users");
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
tv_info = (TextView)findViewById(R.id.tv_info);
resolver = getContentResolver();
}
public void click(View v){
switch (v.getId()) {
case R.id.bt_query:
//建表时的语句:create table t_user(_id integer primary key,uname,upass,money)
query();//调用自定义的查询所有数据的方法
break;
case R.id.bt_insert:
insert();//调用自定义的插入数据的方法
break;
case R.id.bt_update:
//请自行实现
break;
default:
break;
}
}
private void insert() {
//调用自定义的插入数据的方法(硬编码)
ContentValues values = new ContentValues();
values.put("uname", "zhang");
values.put("upass", "321");
values.put("money", "99");
Uri nUri = resolver.insert(uri, values);//sqlite会自动指定主键id
long newId = ContentUris.parseId(nUri);//获取新插入的id
Toast.makeText(this, ""+newId, 0).show();
}
private void query() {
//自定义的查询所有数据的方法
Cursor c = resolver.query(uri , new String[]{"_id","uname","upass","money"}, null, null,null);
String text = "";
while(c.moveToNext()){
text +=c.getString(0)+","+c.getString(1)+","+c.getString(2)+","+c.getString(3)+"\n";
}
tv_info.setText(text);
}
}