一、ContentProvider
使用内容提供者的好处:统一的数据的访问方式
1、注册自定义的内容提供者
<!-- 注册自定义的内容提供者
android:authorities="域名":指定内容提供者的域名
android:name="内容提供者的完整包名+类名":
android:enabled="true":控制当前内容提供者是否可以使用,true:表示可用,是默认值;false:访问失效
android:exported="true":控制当前内容提供者是否可以跨应用程序访问,如果设置为false,则不能跨应用程序访问,是默认值,如果想实现跨应用程序访问,则必须将属性值设为true;
-->
<provider
android:authorities="@string/person_authorities"
android:name=".provider.PersonContentProvider"
android:enabled="true"
android:exported="true"/>
2、内容提供者的编写步骤
-
编写一个子类继承ContentProvider并重写所有的抽象方法:
- onCreate():第一次访问内容提供者时自动调用的方法,用来做初始化操作;只有这个方法在内容解析者中无法访问到,因为没有提供方法onCreate()的方法
- getType():根据指定的URI返回对应的MIMEType类型字符串
- insert():插入数据时自动调用的方法
- update():修改数据时自动调用的方法
- delete():删除数据时自动调用的方法
- query():查询数据时自动调用的方法
-
由于内容提供者是Android四大组件(Activity,Service,ContentProvider,BroadcastReceiver)之一,因此必须在功能清单文件中进行注册.
<provider
android:authorities="com.hsj.example.contentproviderdemo01.provider.personcontentprovider"
android:name=".provider.PersonContentProvider"/>
- 通过域名使用内容解析者访问我们自定义的内容提供者;
this.contentResolver=this.getContentResolver();
person_authorities=this.getResources().getString(R.string.person_authorities);
//查询自定义内容提供者中的数据
Cursor cursor=this.contentResolver.query(
Uri.parse("content://"+person_authorities),
new String[]{"name","age","addr"},
"name like ?",
new String[]{"%小%"},
"_id desc");
//修改自定义内容提供者中的数据
ContentValues values=new ContentValues();
values.put("name","小丽");
int rowCount=this.contentResolver.update(
Uri.parse("content://"+person_authorities),
values,
"name like ?",
new String[]{"%小%"});
//删除自定义内容提供者中的数据
int rowCount=this.contentResolver.delete(
Uri.parse("content://"+person_authorities),
"age=?",
new String[]{String.valueOf(20)});
//插入数据到内容提供者中
ContentValues values=new ContentValues();
values.put("name","张三");
values.put("age",20);
values.put("addr","北京");
Uri uri=this.contentResolver.insert(
Uri.parse("content://"+person_authorities),
values);
//根据指定的uri返回mimeType类型的字符串
String type=this.contentResolver.getType(Uri.parse("content://"+person_authorities));
示例:
/**
* content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
*
* content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/1
*/
public class PersonContentProvider_bak02 extends ContentProvider {
/**
* 声明并实例化Uri匹配器对象并指定默认的匹配码为-1:表示任何域名都不匹配
*/
private static UriMatcher uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
/**
* 声明匹配多条记录的URI对应的匹配码
*/
private static final int MATCH_MULTIPLE_ITEMS = 100;
/**
* 声明匹配单条记录的匹配码
*/
private static final int MATCH_SINGLE_ITEM = 200;
static {
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
uriMatcher.addURI(CommonClass.PERSON_AUTHORITIES,"person",MATCH_MULTIPLE_ITEMS);
/*
#:代表任意数字
*:代表任意字符
* content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/1
*
* uriMatcher.addURI(域名,相对路径(可以有通配符,*:代表任意文本,#:代表任意数字),匹配码(外界给定的URI于指定的匹配规则相符时返回的当前数字));
*/
uriMatcher.addURI(CommonClass.PERSON_AUTHORITIES,"person/#",MATCH_SINGLE_ITEM);
}
/**
* 在内容提供者第一次被访问时自动调用的方法,用来做初始化操作.
* @return true:内容提供者成功加载;false:内容提供者加载失败
*/
@Override
public boolean onCreate() {
return true;
}
/**
* 根据指定的Uri返回相应的MIMEType类型的字符串,
* 如果给定的URI返回的是单条记录,则MIMEType类型字符串以vnd.android.cursor.item开头;
* 如果给定的URI返回的是多条记录,则MIMEType类型字符串以vnd.android.cursor.dir/开头;
* @param uri
* @return
*/
@Override
public String getType(Uri uri) {
String type=null;
//通过对于的uri与uri匹配器中指定的规则进行匹配,和哪个规则匹配成功,则返回匹配规则相符的第三个参数的值,即匹配码的值
int match_code= uriMatcher.match(uri);
switch (match_code){
//匹配多条记录的URI:content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
case MATCH_MULTIPLE_ITEMS:
type="vnd.android.cursor.dir/person";
break;
//匹配单条记录的URI:content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/1
case MATCH_SINGLE_ITEM:
type="vnd.android.cursor.item/person";
break;
default:
break;
}
return type;
}
/**
* 当内容解析者调用insert()方法做插入数据时自动调用的方法
* @param uri
* @param values
* @return
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
int match_code= uriMatcher.match(uri);
switch (match_code){
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
case MATCH_MULTIPLE_ITEMS:
System.out.println("数据插入成功!");
break;
default:
throw new RuntimeException("uri="+uri+"非法,请查证后再进行插入操作!");
}
System.out.println("====PersonContentProvider.insert(Uri uri="+uri+", ContentValues values="+values+")====");
return null;
}
/**
* 当内容解析者调用delete()方法删除数据时自动调用的方法
* @param uri 删除数据时对应的uri
* @param selection where条件表达式
* @param selectionArgs where条件表达式中占位符?的值对应的字符串数组
* @return 本次删除操作受影响的行数
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int match_code= uriMatcher.match(uri);
switch (match_code){
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
case MATCH_MULTIPLE_ITEMS:
System.out.println("删除表中所有记录");
break;
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/123
case MATCH_SINGLE_ITEM:
System.out.println("根据指定的id删除表中的记录");
break;
default:
throw new RuntimeException("非法的uri="+uri);
}
System.out.println("====PersonContentProvider.delete(Uri uri="+uri+", String selection="+selection+", String[] selectionArgs="+Arrays.toString(selectionArgs)+")====");
return 0;
}
/**
* 当内容解析者调用update()修改数据时自动调用的方法
* @param uri 修改数据时给的的uri
* @param values set语句后面的表达式组成的值 update 表名 set name='小丽',age=20 .... where 条件表达式;
* @param selection where条件表达式
* @param selectionArgs where条件表达式中占位符的值
* @return 本次修改受影响的行数
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int match_code= uriMatcher.match(uri);
switch (match_code){
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
case MATCH_MULTIPLE_ITEMS:
System.out.println("修改表中所有记录");
break;
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/123
case MATCH_SINGLE_ITEM:
System.out.println("根据指定的id修改表中的记录");
break;
default:
throw new RuntimeException("非法的uri="+uri);
}
System.out.println("====PersonContentProvider.update(Uri uri="+uri+", ContentValues values="+values+", String selection="+selection+", String[] selectionArgs="+Arrays.toString(selectionArgs)+")=====");
return 0;
}
/**
* 当客户端通过调用内容解析者的query()方法时自动调用的方法
* @param uri 访问当前内容提供者的完整的域名(协议名://简单域名):content://域名;
* @param projection 查询哪些列组成的字符串数组
* @param selection where条件表达式
* @param selectionArgs where条件表达式中占位符的值
* @param sortOrder 排序表达式
* @return 满足指定的条件组成的游标对象
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
int match_code= uriMatcher.match(uri);
switch (match_code){
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person
case MATCH_MULTIPLE_ITEMS:
System.out.println("查询表中所有记录");
break;
//content://com.hsj.example.contentproviderdemo01.provider.personcontentprovider/person/123
case MATCH_SINGLE_ITEM:
System.out.println("根据指定的id查询表中的记录");
break;
default:
throw new RuntimeException("非法的uri="+uri);
}
System.out.println("=====PersonContentProvider.query(Uri uri="+uri+", String[] projection="+ Arrays.toString(projection)+", String selection="+selection+", String[] selectionArgs="+Arrays.toString(selectionArgs)+", String sortOrder="+sortOrder+")====");
return null;
}
}
public class MainActivity_bak02 extends AppCompatActivity {
private ContentResolver contentResolver;
private String person_authorities;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.person_authorities=this.getResources().getString(R.string.person_authorities);
System.out.println("person_authorities="+this.person_authorities);
this.contentResolver=this.getContentResolver();
//查询自定义内容提供者中的数据
//Cursor cursor=this.contentResolver.query(Uri.parse("content://" + person_authorities+"/person"),new String[]{"name","age","addr"},"name like ?",new String[]{"%小%"},"_id desc");
Cursor cursor=this.contentResolver.query(Uri.parse("content://" + person_authorities+"/person/12"),new String[]{"name","age","addr"},"name like ?",new String[]{"%小%"},"_id desc");
System.out.println("cursor="+cursor);
//修改自定义内容提供者中的数据
/* ContentValues values=new ContentValues();
values.put("name","小丽");
// int rowCount=this.contentResolver.update(Uri.parse("content://" + person_authorities+"/person"),values,"name like ?",new String[]{"%小%"});
int rowCount=this.contentResolver.update(Uri.parse("content://" + person_authorities+"/person/12"),values,"name like ?",new String[]{"%小%"});
System.out.println("rowCount="+rowCount);*/
//删除自定义内容提供者中的数据
/* // int rowCount=this.contentResolver.delete(Uri.parse("content://" + person_authorities+"/person"),"age=?",new String[]{String.valueOf(20)});
int rowCount=this.contentResolver.delete(Uri.parse("content://" + person_authorities+"/person/123"),"age=?",new String[]{String.valueOf(20)});
System.out.println("rowCount="+rowCount);*/
//插入数据到内容提供者中
/* ContentValues values=new ContentValues();
values.put("name","张三");
values.put("age",20);
values.put("addr","北京");
Uri uri=this.contentResolver.insert(Uri.parse("content://"+person_authorities+"/person"),values);
System.out.println("uri="+uri);*/
//根据指定的uri返回mimeType类型的字符串
//String type=this.contentResolver.getType(Uri.parse("content://"+person_authorities+"/person"));
//String type=this.contentResolver.getType(Uri.parse("content://"+person_authorities+"/person/100"));
// System.out.println("type="+type);
}
}
二、内容观察者
public class MainActivity extends AppCompatActivity {
private ContentResolver contentResolver;
private String person_authorities;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.person_authorities=this.getResources().getString(R.string.person_authorities);
this.contentResolver=this.getContentResolver();
//注册内容观察者对象,一旦内容发生了变化在内容提供者中对外发送了变化的通知后当前内容观察者中的方法就会自动调用
this.contentResolver.registerContentObserver(Uri.parse("content://"+person_authorities+"/person"), true,new MyContentObserver(new Handler()));
//插入数据到内容提供者中
ContentValues values=new ContentValues();
values.put("name","虾米");
values.put("age",25);
values.put("addr","深圳");
Uri uri=this.contentResolver.insert(Uri.parse("content://"+person_authorities+"/person"),values);
//查询自定义内容提供者中的数据
Cursor cursor=this.contentResolver.query(Uri.parse("content://" + person_authorities + "/person"),new String[]{"id as
_id","name","age","addr"},null,null,"_id desc");
// Cursor cursor=this.contentResolver.query(Uri.parse("content://" + person_authorities + "/person"),new String[]{"id as
_id","name","age","addr"},"name like ?",new String[]{"%小%"},"_id desc");
//Cursor cursor=this.contentResolver.query(Uri.parse("content://" + person_authorities+"/person/11"),new String[]{"id as
_id","name","age","addr"},null,null,"_id desc");
while(cursor.moveToNext()){
int id=cursor.getInt(cursor.getColumnIndex("_id"));
String name=cursor.getString(cursor.getColumnIndex("name"));
int age=cursor.getInt(cursor.getColumnIndex("age"));
String addr=cursor.getString(cursor.getColumnIndex("addr"));
}
}
/**
* 自定义内容观察者需要继承ContentObserver类并提供带一个Handler对象的构造函数,
* 根据需要重新方法
*/
private final class MyContentObserver extends ContentObserver{
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public MyContentObserver(Handler handler) {
super(handler);
}
/**
* 当内容发生变化时自动调用的方法
* @param selfChange
*/
@Override
public void onChange(boolean selfChange) {
}
}
}
三、手机联系人的读取、添加、修改、删除
- 访问通讯录的raw_contacts表中的数据
private String uri_contacts = "content://com.android.contacts/raw_contacts";
- 访问通讯录的data表中指定id的电话
private String uri_contacts_phones = "content://com.android.contacts/data/phones";
- 访问通讯录的data表中指定id的emails
private String uri_contacts_emails = "content://com.android.contacts/data/emails";
- 访问通讯录中的data表的uri
private String uri_contacts_data = "content://com.android.contacts/data";
得到内容解析者对象
this.contentResolver=this.getContentResolver();
1、读取手机联系人
contentResolver的query()完成查询
Cursor cursor_raw_contacts=this.contentResolver.query(Uri.parse(uri_contacts), new String[]{"_id","display_name"}, null, null, "_id DESC");
while(cursor_raw_contacts.moveToNext()){
Map<String,Object> map=new HashMap<String,Object>();
int _id=cursor_raw_contacts.getInt(cursor_raw_contacts.getColumnIndex("_id"));
String display_name=cursor_raw_contacts.getString(cursor_raw_contacts.getColumnIndex("display_name"));
map.put("id",_id);
map.put("display_name",display_name);
System.out.println("raw_contact=====_id="+_id+",display_name="+display_name);
//如下代码取电话号码
//select raw_contact_id,data1 from data d,raw_contacts rc where raw_contact_id=rc._id and mimetype_id=5;
Cursor cursor_phone=this.contentResolver.query(Uri.parse(uri_contacts_phones), new String[]{"raw_contact_id", "data1"},
"raw_contact_id=?", new String[]{String.valueOf(_id)}, null);
StringBuilder sb_phones=new StringBuilder();
while(cursor_phone.moveToNext()){
String phone=cursor_phone.getString(cursor_phone.getColumnIndex("data1"));
sb_phones.append(phone+" | ");
}
if(sb_phones.length()>0){
sb_phones.delete(sb_phones.length()-3, sb_phones.length());
}
map.put("phones",sb_phones.toString());
//如下代码取email
//select raw_contact_id,data1 from data d,raw_contacts rc where d.raw_contact_id=rc._id and mimetype_id=1;
Cursor cursor_email=this.contentResolver.query(
Uri.parse(uri_contacts_emails),
new String[]{"raw_contact_id", "data1"},
"raw_contact_id=?",
new String[]{String.valueOf(_id)}, null);
StringBuilder sb_emails=new StringBuilder();
while(cursor_email.moveToNext()){
String email=cursor_email.getString(cursor_email.getColumnIndex("data1"));
sb_emails.append(email+" | ");
}
if(sb_emails.length()>0){
sb_emails.delete(sb_emails.length()-3, sb_emails.length());
}
map.put("emails",sb_emails.toString());
data.add(map);
}
2、添加手机联系人
ContentValues values=new ContentValues();
// 往raw_contacts表中插入一条空数据,目的是获取联系人的id
Uri new_uri=contentResolver.insert(Uri.parse(uri_contacts), values);
//content://com.android.contacts/raw_contacts/4
//最新插入联系人的id
long id= ContentUris.parseId(new_uri);
// 往data表中插入联系人姓名的数据
values.put("raw_contact_id", id);
values.put("mimetype", "vnd.android.cursor.item/name");
values.put("data1", "小倩");
contentResolver.insert(Uri.parse(uri_contacts_data), values);
// 往data表中插入联系人的电话信息
values.clear();
values.put("raw_contact_id", id);
values.put("mimetype", "vnd.android.cursor.item/phone_v2");
values.put("data1", "13512011014");
contentResolver.insert(Uri.parse(uri_contacts_data), values);
// 往data表中插入联系人的email
values.clear();
values.put("raw_contact_id", id);
values.put("mimetype", "vnd.android.cursor.item/email_v2");
values.put("data1", "xiaoqian@sohu.com");
contentResolver.insert(Uri.parse(uri_contacts_data), values);
3、删除手机联系人
/**
* 根据联系人的姓名删除联系人
* @param displayName 联系人的姓名
* @return 删除是否成功
*/
private boolean deleteContactByDisplayName(String displayName) {
int row_count=this.contentResolver.delete(
Uri.parse(uri_contacts),
"display_name=?",
new String[]{displayName});
return row_count>0;
}
4、修改手机联系人
/**
* 根据联系人id修改联系人
* @param id
* @return
*/
private boolean updateContactById(String id) {
ContentValues values = new ContentValues();
values.put("display_name", displayName);
//raw_contact
int count_rawContacts=this.contentResolver.update(
Uri.parse(uri_contacts),
values,
"_id=?",
new String[]{String.valueOf(id)});
values.clear();
values.put("data1", displayName);
int count_data1=this.contentResolver.update(
Uri.parse(uri_contacts_data),
values,
"raw_contact_id=? and mimetype_id=?",
new String[]{String.valueOf(id),"7"});
values.clear();
values.put("data1", phones);
int count_data2=this.contentResolver.update(
Uri.parse(uri_contacts_data),
values,
"raw_contact_id=? and mimetype_id=?",
new String[]{String.valueOf(id),"5"});
values.clear();
values.put("data1", emails);
int count_data3=this.contentResolver.update(
Uri.parse(uri_contacts_data),
values,
"raw_contact_id=? and mimetype_id=?",
new String[]{String.valueOf(id),"1"});
if(count_data1>0 && count_data2>0 && count_data3>0 && count_rawContacts>0){
return true;
}
return false;
}
四、操作手机短信
1、注册读取手机短信的权限
<uses-permission android:name="android.permission.READ_SMS"/>
2、操作手机短信
/**
* 读取手机短信的地址
*/
private String smsuri = "content://sms";
private List<Map<String, Object>> getData() {
this.data=new ArrayList<>();
Cursor cursor=this.contentResolver.query(
Uri.parse(smsuri),
new String[]{"address","type","date","body"},
null,null,null);
while(cursor.moveToNext()){
Map<String,Object> map=new HashMap<>();
String address=cursor.getString(cursor.getColumnIndex("address"));
int type=cursor.getInt(cursor.getColumnIndex("type"));
long date=cursor.getLong(cursor.getColumnIndex("date"));
String body=cursor.getString(cursor.getColumnIndex("body"));
map.put("address",address);
String strType="";
switch (type){
case 1:
strType="接收的短信";
break;
case 2:
strType="发送的短信";
break;
}
map.put("type",strType);
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strDate=simpleDateFormat.format(date);
map.put("date",strDate);
map.put("body",body);
this.data.add(map);
}
return this.data;
}
五、查询手机通话记录
1、注册读取通话记录的权限
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
2、操作手机通话记录
/**
* 访问手机通话记录的地址
*/
private String call_log_uri = "content://call_log/calls";
private List<Map<String, Object>> getData() {
this.data=new ArrayList<>();
//字段名 asc:升序,desc降序
Cursor cursor=this.contentResolver.query(Uri.parse(call_log_uri),new String[]{"number","type","date"},null,null,"_id DESC");
while(cursor.moveToNext()){
Map<String,Object> map=new HashMap<>();
String number=cursor.getString(cursor.getColumnIndex("number"));
int type=cursor.getInt(cursor.getColumnIndex("type"));
long date=cursor.getLong(cursor.getColumnIndex("date"));
map.put("number",number);
String typeStatus="";
switch (type){
//表示接听电话
case 1:
typeStatus="接听电话";
break;
//表示呼叫电话
case 2:
typeStatus="呼叫电话";
break;
//未接来电
case 3:
typeStatus="未接来电";
break;
}
map.put("type",typeStatus);
Date localDate=new Date(date);
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strDate= simpleDateFormat.format(localDate);
map.put("date",strDate);
this.data.add(map);
}
return this.data;
}