一个应用实现ContentProvider来提供内容给别的应用来操作,
一个应用通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。
1.ContentPrevider:
什么是?
五大数据存储方式之一
ContentProvider为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。统一了数据访问方式。
引入的原因:
数据库在android中是私有的,不能跨进程访问
ContentProvider统一了数据访问方式,外界无需关心数据是怎么存储的,我们可以通过一套接口,或者标准和程序中的数据
打交道,对数据进行修改
ContentResolver(操作应用暴露的数据,及可使用此类对象进行增删查改)
通过ContentResolver resolver = getContentResolver();获得对象进行操作
查询方法:
/**
* 参数1 uri:访问地址uri
* 参数2 projection:返回查询的列,当null的时候是所有的列
* 参数3 selection:筛选条件
* 参数4 selectionArgs: 筛选条件的值
* 参数5 sortOrder:按某个字段排序
* 返回值为Cursor
*/
Cursor cursor = resolver.query(uri, null, null, null, null);
2.知识点:
SimpleCursorAdapter:游标适配器
/**
* 参数1:上下文对象
* 参数2:列表item的布局视图
* 参数3:查询结果的返回值,是一个集合Cursor
* 参数4:字符串数组,值为Cursor集合中的列名,
* 把列名对应的值绑定到UI上(系统实现了)
* 参数5:整形数组,其中值为Cursor列名值多对应的控件
*
*/
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, new String[]{"number"}, new int[]{R.id.textView1});
Uri:统一资源定位符,根Uri操作相关的类必须借助ContentResolver
每个ContentProvider都有一个公共的Uri(表示此contentProvider代表的数据)
Android所提供的ContentProvider都存放在android.provider包当中
所有URI都以“content://”开头,其中“content:”是用来标识数据是由Content Provider管理的schema.
主要Uri有:
content://sms/ 所有短信
content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱
content://sms/failed 发送失败
content://sms/queued 待发送列表
UriMatcher:用于匹配Uri
ContentUris:可对contentUri后追加id,也可直接取出contentUri中的id
ContentUris.appendId() 方法
ContentUris.withAppendedId(contentUri, id) 在原有uri上追加id,自定义ContentProvider的时候,增删改的时候,追加目标id
ContentResolver:(操作应用暴露的数据,及可使用此类对象进行增删查改)ContentProvider的所有操作都通过ContentResolver 实现
ContentResolver resolver = getContentResolver();
Bitmap中compress()方法:通过流写图片
OutputStream os = resolver.openOutputStream(uri);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
/**
* 参数1 format:图片格式(固定为CompressFormat.JPEG)
* 参数2 quality:图片质量 0-100
* 参数3 stream:输出流
*/
bmp.compress(CompressFormat.JPEG, 100, os);
访问通讯录:
1)联系人的数据库文件的位置 /data/data/com.android.providers.contacts/databases/contacts2.db
contacts表:保存了ContactID。区分不同的人,无具体信息。该表不能进行增删改查
该表保存了联系人的id和名称以及是否有电话号码(has_phone_number),是否被添加?到收藏夹等信息。
Rows代表不同的人,这些人基于raw contact 的行的集合(无法直接向此表插入数据)(区分不同的人,无具体信息)
raw_contacts表:保存了RawContactID和ContactID
Rows包含一个人的简要数据,特指用户账户和类型(在此表中进行联系人的增删查改)
mimetypes表:该表定义了所有的 MimeTypeID,即联系人的各个字段的唯一标志。
Rows包含raw contact的具体数据信息,例如电子邮件或者电话号码(通过raw_contact或者contact任意一个表都能取出任何一个人的具体信息,其中mime_type区别数据类型)
data表:保存了两个ID:MimeTypeID和RawContactID
联系人的所有信息保存在列data1至data15中,各列中保存的内容根据MimeTypeID的不同而不同。如保存号码(MimeTypeID=5)的那行数据中,
data1列保存号码,data2列保存号码类型(手机号码/家庭号码/工作号码等)。
注:一个contacts表对应多个 raw_contacts表 ,一个raw_contacts表又对应多个data表
3)操作:这里只写了查询通讯录操作:
方法一:a:从contacts表去查联系人id
b:根据id,去data表中匹配联系人,找详细数据
Demo:
public static List queryAllContacts(Context ctx) {
// 查询联系人:Contacts:区别不同的人(没有个人具体信息),通过id和昵称。
// URi地址
Uri uri = Contacts.CONTENT_URI;
ContentResolver resolver = ctx.getContentResolver();
Cursor cursor = resolver.query(uri, null, null, null, null);
List persons = new ArrayList();
Person p = new Person();
// 取contact表的id
while (cursor.moveToNext()) {
// 方式1,获得
int _id = cursor.getInt(cursor.getColumnIndex("_id"));
// 方式2,获得
String name = cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME));
Log.e("-----", "---id---" + _id);
Log.e("-----", "---name---" + name);
p.setId(_id);
p.setName(name);
// 在data表查询具体信息,根据contact_id匹配查询具体人的信息
// String字符串地址:content://com.android.contacts/data
Cursor c = resolver.query(Data.CONTENT_URI, null, "contact_id = ?", new String[] { String.valueOf(_id) },
null);
// 取data表详细内容,cursor代表一个结果集,用集合来存储
List infos = new ArrayList();
Info info = new Info();
while (c.moveToNext()) {
// 此字段标识取出的值是电话还是邮箱等其他内容
String type = c.getString(c.getColumnIndex("mimetype"));
// 匹配电话与email
if (type.equals("vnd.android.cursor.item/phone_v2")) {
// data1放的是值
Log.e("-----", "匹配电话" + c.getString(c.getColumnIndex(Data.DATA1)));
info.setNumber(c.getString(c.getColumnIndex(Data.DATA1)));
} else if (type.equals("vnd.android.cursor.item/email_v2")) {
Log.e("-----", "匹配邮件" + c.getString(c.getColumnIndex(Data.DATA1)));
info.setEmail(c.getString(c.getColumnIndex(Data.DATA1)));
}
}
p.setList(infos);
persons.add(p);
}
return persons;
}
方法二:a:从raw_contact表去查id
b:根据id,去data表中匹配联系人,找详细数据
Demo:
public static List queryAllContacts(Context ctx) {
Uri uri = RawContacts.CONTENT_URI;
ContentResolver resolver = ctx.getContentResolver();
Cursor cursor = resolver.query(uri, null, null, null, null);
List persons = new ArrayList();
Person p = new Person();
// 取contact表的id
while (cursor.moveToNext()) {
// 方式1,获得id
int _id = cursor.getInt(cursor.getColumnIndex("_id"));
// 方式2,获得name
String name = cursor.getString(cursor.getColumnIndex(RawContacts.DISPLAY_NAME_ALTERNATIVE));
Log.e("-----", "---id---" + _id);
Log.e("-----", "---name---" + name);
p.setId(_id);
p.setName(name);
// 在data表查询具体信息,根据raw_contact_id匹配查询具体人的信息
Cursor c = resolver.query(Data.CONTENT_URI, null, "raw_contact_id = ?", new String[] { String.valueOf(_id) },
null);
// 取data表详细内容,cursor代表一个结果集,用集合来存储
List infos = new ArrayList();
Info info = new Info();
while (c.moveToNext()) {
// 此字段标识取出的值是电话还是邮箱等其他内容
String type = c.getString(c.getColumnIndex("mimetype"));
// 匹配电话与email
if (type.equals("vnd.android.cursor.item/phone_v2")) {
// data1放的是值
Log.e("-----", "匹配电话" + c.getString(c.getColumnIndex(Data.DATA1)));
info.setNumber(c.getString(c.getColumnIndex(Data.DATA1)));
} else if (type.equals("vnd.android.cursor.item/email_v2")) {
Log.e("-----", "匹配邮件" + c.getString(c.getColumnIndex(Data.DATA1)));
info.setEmail(c.getString(c.getColumnIndex(Data.DATA1)));
}
}
p.setList(infos);
persons.add(p);
}
return persons;
}
访问图库
权限
1)查询图片库步骤:Uri地址:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
a: 获取Contentresolver对象
ContentResolver resolver = getContentResolver();
b: 调用query()方法,返回Cursor对象
Cursor c = r.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
c: 根据cursor对象获取图库的常中图片的常用字段:
图片id: _id (MediaStore.Images.Media._ID),
图片名称: _display_name (MediaStore.Images.Media.DISPLAY_NAME),
图片类型: mime_type (MediaStore.Images.Media.MIME_TYPE),
图片地址: _data (MediaStore.Images.Media.DATA)
例子:获得图片地址的两种方式:
//方式一:
String date = c.getString(c.getColumnIndex(Images.Media.DATA));
//方式二:
String data = c.getString(c.getColumnIndex(“_data”));
2)插入图片库步骤:插入图库的Uri地址:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
a: 获取Contentresolver对象
ContentResolver resolver = getContentResolver();
b:通过ContentValues对图片进行配置
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, “gg.png”);
values.put(MediaStore.Images.Media.MIME_TYPE, “image/jpeg”);//注意类型,固定
c:调用insert()方法插入,并返回Uri对象为插入图片的具体地址
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
d: 根据Uri对象获取图片的输出流(getContentResolver().openOutputStream(uri)),将图片写入到输出流中并刷新输出流且关闭输出流
OutputStream os = resolver.openOutputStream(uri);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
/** 将图片写入到输出流
* 参数1 format:图片格式
* 参数2 quality:图片质量 0-100
* 参数3 stream:输出流
*/
bmp.compress(CompressFormat.JPEG, 100, os);
os.flush();
os.close();
图库中图片属性的所有信息:
_id
_data
_size
_display_name
mime_type
title
date_added
date_modified
description
picasa_id
isprivate
latitude
longitude
datetaken
orientation
mini_thumb_magic
bucket_id
bucket_display_name
width
height
5.SearchView:
属性:android:iconifiedByDefault=""
值为true,表示初始搜索框是关闭的,仅显示一个放大镜;
值为false搜索框是打开的
android:imeOptions=""
软键盘右下角的行为操作,值可以是搜索、下一个、发送、完成等等
android:queryHint输入框默认文本
监听:.setOnQueryTextListener 实现两个抽象方法
onQueryTextSubmit(String query):开始搜索
onQueryTextChange(String newText):输入框内容变化的监听器
6.AutoCompleteTextView:自动匹配
属性:可以在java文件中设置也可以在XNL中设置
.setDropDownHeight方法 ,用来设置提示下拉框的高度,注意,这只是限制了提示下拉框的高度,提示数据集的个数并没有变化
.setThreshold方法,设置从输入第几个字符起出现提示
.setCompletionHint方法,设置提示框最下面显示的文字
.showdropdown方法,让下拉框弹出来
Demo:
//下拉框的高度
auto.setDropDownHeight(500);
//从第几个字母开始匹配
auto.setThreshold(1);
//提示信息
auto.setCompletionHint("最近搜索历史");
监听:.setOnFocusChangeListener(new OnFocusChangeListener() {
//焦点改变
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus){
//展示提示框
auto.showDropDown();
}
}
});
访问短信:
Uri地址:Telephony.Sms.CONTENT_URI
字符串:content://sms
方式1:通过字符串类型访问,content://sms
步骤:
a:声明一个字符串,内容为content://sms
String sms = "content://sms";
b:用Uri(统一资源定位符进行转码)
Uri uri = Uri.parser(sms);
c:获取ContentResolver对象
ContentResolver resolver = getContentResolver();
d:调用query()方法,返回Cursor对象
Cursor cursor = resolver.query(uri, null, null, null, null);
e: 根据cursor对象进行操作:
与ListView的一起使用
SimpleCursorAdapter adapter = new SimpleCursorAdapter(MainActivity.this, R.layout.item, cursor, new String[]{"address","body","date"},
new int[]{R.id.tel,R.id.body,R.id.date},SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
listView.setAdapter(adapter);
方式二:Uri类型,Telephony.Sms.CONTENT_URI
步骤:
a: 获取Contentresolver对象
ContentResolver resolver = getContentResolver();
b: 调用query()方法,返回Cursor对象
Cursor cursor1 = resolver.query(Telephony.Sms.CONTENT_URI, null, null, null, null);
c:根据cursor对象获取短信的常用字段:_id,address,person,body,type,date,read
短信库中所有的类型:
_id 短消息序号
thread_id
address 发件人地址,手机号
person 发件人,返回一个数字就是联系人表里的序号,陌生人为null,
date 日期,long型
date_sent
protocol
read 是否阅读,0未读,1已读
status
type
reply_path_present
subject
body 消息内容
service_center
locked
error_code
seen
访问通话记录: Uri地址:CallLog.Calls.CONTENT_URI
字符串:content://call_log/calls
权限:
步骤:
a: 获取Contentresolver对象
ContentResolver resolver = getContentResolver();
b: 调用query()方法,返回Cursor对象
Cursor cursor = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, null);
c:根据cursor对象进行操作
与listView的一起使用
/**
* 参数1:上下文对象
* 参数2:列表item的布局视图
* 参数3:查询结果的返回值,是一个集合Cursor
* 参数4:字符串数组,值为Cursor集合中的列名,
* 把列名对应的值绑定到UI上(系统实现了)
* 参数5:整形数组,其中值为Cursor列名值多对应的控件
*
*/
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, new String[]{"number"}, new int[]{R.id.textView1});
listView.setAdapter(adapter);
//监听
listView.setOnItemClickListener(new OnItemClickListener()
Android通话记录数据库的字段介绍
formatted_number
numbertype 电话号码类型(家庭,工作等)
duration 通话时长
presentation
geocoded_location
lookup_uri
countryiso
transcription
subscription
subscription_id
photo_id
mark_content
_id 主键
type 电话类型(来电1,打出去2,未接3,语音邮件4)
is_read
number 电话号码
voicemail_uri
features
new
date 通话日期
data_usage
numberlabel
mark_type
subscription_component_name
mark_count
name
is_cloud_mark
matched_number
normalized_number
is_private
ring_times