Content providers是用来管理对结构化数据集进行访问的一组接口。这组接口对数据进行封装,并提供了用于定义数据安全的机制。Content providers是一个进程使用另一个进程数据的标准接口。
Android系统本身也通过content providers来管理数据,如音频,视频,图像,个人联系信息等。我们可以在android.provider包的参考文档中看到这些providers列表。在一定条件下,这些providers能够访问任何Android应用程序。
providers最主要的目的是为了让其他应用程序使用provider的客户端对象访问provider。所以,providers和provider客户端共同提供了一个一致的标准数据接口用来处理进程间通信和安全的数据访问。
定义ContentProvider继承该类,实现相关方法:
@Override
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {
return null;
}
@Override
public Uri insert(Uri uri,ContentValues values) {
return null;
}
@Override
public int delete(Uri uri,String selection,String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs) {
return 0;
}
@Override
public boolean onCreate() {
return false;
}
@Override
public String getType(Uri uri) {
return null;
}
在里面实现增删改查、onCreate和getType方法(实际项目中,即使用不到也要写上这六个方法,再根据需求实现相应的方法);定义主机名;定义编码,对应路径;定义类型;在处理的时候用Uri的匹配器检查uri实现对应的方法。
下面是测试时ContentProvider部分的代码:
package com.example.contentprovider;
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;
//自定义ContentProvider
public class HelloContentProvider extends ContentProvider {
//定义主机名
private static final String authority="com.example.contentprovider.hellocontentprovider";
//创建一个Uri的匹配器
private static UriMatcher uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
//定义匹配码
private static final int single_code=2;//返回单个记录的匹配码
private static final int multiple_code=1;//返回多个记录的匹配码
//定义两种不同的类型 text/plain image/jpg
private static final String single_type="vnd.android.cursor.item/person";
private static final String multiple_type="vnd.android.cursor.dir/person";
static {
//当传来的路径是content://com.example.contentprovider.hellocontentprovider/person
uriMatcher.addURI(authority,"person",1);
//当传来的路径是content://com.example.contentprovider.hellocontentprovider/person/1
uriMatcher.addURI(authority,"person/#",2);
}
private DatabaseAdapter.DatabaseHelper databaseHelper;
//创建数据存储后端,如数据库,文件,网络接口等,这里主要进行初始化工作
@Override
public boolean onCreate() {
databaseHelper=new DatabaseAdapter.DatabaseHelper(getContext());
return false;
}
//查询符合指定条件的记录
@Override
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {
switch (uriMatcher.match(uri)){
//content://com.example.contentprovider.hellocontentprovider/person/1
case single_code:
SQLiteDatabase database=databaseHelper.getReadableDatabase();
long id=ContentUris.parseId(uri);
selection= PersonMetadata.Person._ID+"=?";
selectionArgs= new String[]{String.valueOf(id)};
return database.query(PersonMetadata.Person.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
//content://com.example.contentprovider.hellocontentprovider/person
case multiple_code:
database=databaseHelper.getReadableDatabase();
return database.query(PersonMetadata.Person.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
}
return null;
}
//基于给定URI,返回URI表示的MIME类型
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case single_code:
return single_type;
case multiple_code:
return multiple_type;
}
return null;
}
//插入一个新的记录
//content://com.example.contentprovider.hellocontentprovider/person/4
@Override
public Uri insert(Uri uri,ContentValues values) {
switch (uriMatcher.match(uri)){
case multiple_code:
SQLiteDatabase database=databaseHelper.getWritableDatabase();
long id=database.insert(PersonMetadata.Person.TABLE_NAME,null,values);
uri=ContentUris.withAppendedId(uri,id);
database.close();
break;
}
return uri;
}
//删除符合指定条件的记录
@Override
public int delete(Uri uri,String selection,String[] selectionArgs) {
switch (uriMatcher.match(uri)){
//content://com.example.contentprovider.hellocontentprovider/person/1
case single_code:
SQLiteDatabase database=databaseHelper.getWritableDatabase();
long id=ContentUris.parseId(uri);
selection= PersonMetadata.Person._ID+"=?";
selectionArgs= new String[]{String.valueOf(id)};
int row=database.delete(PersonMetadata.Person.TABLE_NAME,selection,selectionArgs);
database.close();
return row;
//content://com.example.contentprovider.hellocontentprovider/person
case multiple_code:
database=databaseHelper.getWritableDatabase();
row=database.delete(PersonMetadata.Person.TABLE_NAME,selection,selectionArgs);
database.close();
return row;
}
return 0;
}
//更新指定条件的记录
@Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs) {
switch (uriMatcher.match(uri)){
//content://com.example.contentprovider.hellocontentprovider/person/1
case single_code:
SQLiteDatabase database=databaseHelper.getWritableDatabase();
long id=ContentUris.parseId(uri);
selection= PersonMetadata.Person._ID+"=?";
selectionArgs= new String[]{String.valueOf(id)};
int row=database.update(PersonMetadata.Person.TABLE_NAME,values,selection,selectionArgs);
database.close();
return row;
//content://com.example.contentprovider.hellocontentprovider/person
case multiple_code:
database=databaseHelper.getWritableDatabase();
row=database.update(PersonMetadata.Person.TABLE_NAME,values,selection,selectionArgs);
database.close();
return row;
}
return 0;
}
}
另外,还需要在清单文件中进行声明provider,并在其中配置ContentProvider,这样,别人就可以通过provier,找到该ContentProvider并访问。ContentProvider采用了authorities(主机名/域名)对它进行唯一标识
注意:标准写法authorities里一般为小写地址
UriMarcher(uri匹配器)和ContentUris工具类
当外部应用需要对ContentProvider 中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Activity提供的getContentResolver()方法。ContentResolver cr = getContentResolver();
ContentResolver类提供了与ContentProvider类相同的四个方法:
通过ContentResolver()方法访问ContentProvider,再调用方法实现功能
package com.example.contentprovider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void addClick(View view){
ContentResolver contentResolver=this.getContentResolver();
//content://com.example.contentprovider.hellocontentprovider/person
//content://com.example.contentprovider.hellocontentprovider/person/1
//调用ContentProvider的添加方法
Uri uri=Uri.parse("content://com.example.contentprovider.hellocontentprovider/person");//content是ContentProvider协议头
ContentValues values=new ContentValues();
values.put(PersonMetadata.Person.NAME,"路飞");
values.put(PersonMetadata.Person.AGE,19);
contentResolver.insert(uri,values);
}
public void deleteClick(View view){
ContentResolver contentResolver=this.getContentResolver();
Uri uri=Uri.parse("content://com.example.contentprovider.hellocontentprovider/person/1");
contentResolver.delete(uri,null,null);
}
public void updateClick(View view){
ContentResolver contentResolver=this.getContentResolver();
Uri uri=Uri.parse("content://com.example.contentprovider.hellocontentprovider/person/1");
ContentValues values=new ContentValues();
values.put(PersonMetadata.Person.NAME,"索罗");
values.put(PersonMetadata.Person.AGE,"21");
contentResolver.update(uri,values,null,null);
}
public void findClick(View view){
ContentResolver contentResolver=this.getContentResolver();
Uri uri=Uri.parse("content://com.example.contentprovider.hellocontentprovider/person");
Cursor c=contentResolver.query(uri,null,null,null,null);
while (c.moveToNext()){
System.out.println(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person._ID)));
System.out.println(c.getString(c.getColumnIndexOrThrow(PersonMetadata.Person.NAME)));
System.out.println(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person.AGE)));
}
c.close();
}
}
package com.example.contentprovider;
//实体类
public class Person {
private int id;
private String name;
private int age;
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Person( String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{"+
"id="+id+
",name='"+name+"\'"+
",age='"+age+"\'"+
"}";
}
}
创建一个数据库常量类
package com.example.contentprovider;
import android.provider.BaseColumns;
//数据库常量类
public class PersonMetadata {
public static abstract class Person implements BaseColumns {
public static final String TABLE_NAME="person";
public static final String NAME="name";
public static final String AGE="age";
}
}
数据库类,在里面定义DatabaseHelper方法以及增删改查操作
package com.example.contentprovider;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
//创建数据库类
public class DatabaseAdapter {
private DatabaseHelper databaseHelper;
public DatabaseAdapter(Context context){
databaseHelper=new DatabaseHelper(context);
}
public void save(Person person){
SQLiteDatabase database=databaseHelper.getWritableDatabase();
String sql="insert into person(name,age) values(?,?)";
Object[] args={person.getName(),person.getAge()};
database.execSQL(sql,args);
database.close();
}
public void delete(int id){
SQLiteDatabase database=databaseHelper.getWritableDatabase();
String sql="delete from person where _id=?";
Object[] args={id};
database.execSQL(sql,args);
database.close();
}
public void update(Person person){
SQLiteDatabase database=databaseHelper.getWritableDatabase();
String sql="update person set name=?,age=? where _id=?";
Object[] args={person.getName(),person.getAge(),person.getId()};
database.execSQL(sql,args);
database.close();
}
public ArrayList findAll(){
SQLiteDatabase database=databaseHelper.getReadableDatabase();
String sql="select _id,name,age from person";
Cursor c=database.rawQuery(sql,null);
ArrayList people=new ArrayList<>();
Person person=null;
while (c.moveToNext()){
person=new Person();
person.setId(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person._ID)));
person.setName(c.getString(c.getColumnIndexOrThrow(PersonMetadata.Person.NAME)));
person.setAge(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person.AGE)));
people.add(person);
}
c.close();
database.close();
return people;
}
public Person findById(int id){
SQLiteDatabase database=databaseHelper.getReadableDatabase();
String sql="select _id,name,age from person where _id=?";
Cursor c=database.rawQuery(sql,new String[]{String.valueOf(id)});
Person person=null;
if (c.moveToNext()){
person=new Person();
person.setId(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person._ID)));
person.setName(c.getString(c.getColumnIndexOrThrow(PersonMetadata.Person.NAME)));
person.setAge(c.getInt(c.getColumnIndexOrThrow(PersonMetadata.Person.AGE)));
}
c.close();
database.close();
return person;
}
private static class DatabaseHelper extends SQLiteOpenHelper{
private static final String DB_NAME="cp.db";
private static final int VERSION=1;
private static final String create_table="create table person(_id integer primary key autoincrement,"+
"name text,age integer)";
private static final String drop_tabel="drop table if exists person";
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(create_table);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(drop_tabel);
db.execSQL(create_table);
}
}
}
查询联系人
权限添加
package com.example.contentprovider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.media.Image;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class ContactsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contacts);
}
//添加联系人
public void contactAddClick(View view){
ContentResolver contentResolver=getContentResolver();
//执行一个控制插入,目的是获取系统返回的rawContactId
ContentValues values=new ContentValues();
Uri uri=contentResolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
long _id= ContentUris.parseId(uri);
//插入姓名数据
values.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID,_id);
values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,"JACK");
contentResolver.insert(ContactsContract.Data.CONTENT_URI,values);
//插入电话数据
values.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID,_id);
values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,"0099");
values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
contentResolver.insert(ContactsContract.Data.CONTENT_URI,values);
Toast.makeText(this, "记录已添加", Toast.LENGTH_SHORT).show();
}
//删除联系人
public void contactDeleteClick(View view){
ContentResolver contentResolver=getContentResolver();
System.out.println(ContactsContract.Contacts.CONTENT_URI.toString()+"/3");
Uri uri=Uri.parse("content://com.android.contacts/contacts/3");
contentResolver.delete(uri,null,null);
Toast.makeText(this, "记录已删除", Toast.LENGTH_SHORT).show();
}
//修改联系人
public void contactUpdateClick(View view){
ContentResolver contentResolver=getContentResolver();
ContentValues values=new ContentValues();
values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,"4455");
values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
contentResolver.update(ContactsContract.Data.CONTENT_URI,values,"_id=1",null);
Toast.makeText(this, "_id=1的记录已更新", Toast.LENGTH_SHORT).show();
}
//查询联系人
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void contactFindClick(View view){
ContentResolver contentResolver=this.getContentResolver();
String id=null;
String mimetype=null;
/*
只需要从Contacts中获取ID,其他的都可以不要,通过查看上面翻译的SQL语句,
可以看出将第二个参数设置成null,默认返回的列异常多,是一种资源浪费
*/
Cursor cursor=contentResolver.query(ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID},null,null,null,null);
while (cursor.moveToNext()){
id=cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
//从一个Cursor获取的信息
Cursor contactInfoCursor=contentResolver.query(
ContactsContract.Data.CONTENT_URI,
new String[]{ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.DATA1,ContactsContract.Data.DATA15},
ContactsContract.Data.CONTACT_ID+"="+id,null,null);
while (contactInfoCursor.moveToNext()){
mimetype=contactInfoCursor.getString(contactInfoCursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE));
String value=contactInfoCursor.getString(contactInfoCursor.getColumnIndexOrThrow(ContactsContract.Data.DATA1));
byte[] photo=contactInfoCursor.getBlob(contactInfoCursor.getColumnIndexOrThrow(ContactsContract.Data.DATA15));
if (mimetype.contains("/name")){
System.out.println("姓名="+value);
}else if (mimetype.contains("/im")){
System.out.println("聊天(QQ)账号="+value);
}else if (mimetype.contains("/email")){
System.out.println("邮箱="+value);
}else if (mimetype.contains("/phone")){
System.out.println("电话="+value);
}else if (mimetype.contains("/postal-address_v2")){
System.out.println("地址="+value);
}else if (mimetype.contains("/photo")){
System.out.println("照片="+photo);
}else if (mimetype.contains("/group")){
System.out.println("组="+value);
}
}
System.out.println("----------------------");
contactInfoCursor.close();
}
cursor.close();
}
}