概述
在Android开发中采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据等等。
ContentProvider作为Android四大组件之一,一般为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。
ContentProvider的使用
1.ContentProvider的实现:
(1)新建类MyProvider.java继承ContentProvider,并实现其增删改查等六个方法。
方法名 | 说明 |
---|---|
onCreate | 主要用来初始化使用到的工具,在ContentProvider对象创建之后就会被调用。 |
query | 通过对数据库具有可读权限对象的query方法,完成外部应用数据库关于表的查询操作。 |
insert | 通过对数据库具有可写权限对象的insert方法,完成数据库关于表的插入操作。 |
delete | 通过对数据库具有可写权限对象的delete方法,完成数据库中关于表的删除操作。 |
update | 通过对数据库具有可写权限对象的update方法,完成数据库中关于表的更新操作。 |
getType | 用来标识ContentProvider中数据的类型。其中如果 URI 模式用于单个行为android.cursor.item/,如果 URI 模式用于多个行为android.cursor.dir/。 |
(2)在AndroidManifest.xml对ContentProvider进行配置,为了能让其他应用找到该ContentProvider ,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识。
<provider
android:authorities="com.example.myProvider"
android:name=".MyProvider"/>
其中android:authorities 授权,表示外部应用程序访问当前内容提供者的标识符,一般是以 “包名 + 类名” 的形式来定义的。
android:name表示实现 ContentProvider 的类。
2.ContentProvider中的Uri:
比如:content://com.example.myProvider/table/666
格式为scheme://authority/Path/Id
字段 | 说明 |
---|---|
scheme | 为固定值content,表示访问内容提供者 |
authority | 授权信息,用以区别不同的ContentProvider,也就是清单文件中provider节点中的authorites属性 |
Path | 表名,用以区分ContentProvider中不同的数据表 |
Id | Id号,用以区别表中的不同数据 |
3.UriMatcher类:
UriMatcher类用来匹配Uri,使用match()方法匹配路径时返回匹配码。
addURI(authority, path, code)方法说明:
参数 | 说明 |
---|---|
authority | 用于标识唯一一个ContentProvider,和清单文件中的authorities属性相同 |
path | 路径,一般为表名,*表示匹配任意字符,#表示匹配数字 |
code | 返回值,匹配路径成功的返回值 |
比如:
private static final String AUTHORITY = "com.example.myProvider";
private static final int MATCH_ALL_CODE = 200;
private static final int MATCH_ONE_CODE = 201;
private static UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "student", MATCH_ALL_CODE);
uriMatcher.addURI(AUTHORITY, "student/#", MATCH_ONE_CODE);
}
其中”uriMatcher.addURI(AUTHORITY, “student/#”, MATCH_ONE_CODE);”
表示如果match(uri)方法匹配content://com.example.myProvider/student/#路径,返回匹配码为201。
4.ContentUris类:
ContentUris类用于操作Uri路径后面的ID部分,主要是两个方法。
(1)在Uri路径加上ID:
ContentUris.withAppendedId(uri, id);
(2)从Uri中获取ID:
long id = ContentUris.parseId(uri);
5.ContentResolver:
使用ContentResolver对象来对ContentProvider中的数据进行增删改查的操作或是监听数据的变化。
(1)插入数据:
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.myProvider/student");
ContentValues contentValues = new ContentValues();
contentValues.put("name", "Test");
contentValues.put("phone", "123);
contentResolver.insert(uri, contentValues);
(2)更新数据:
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.myProvider/student/1");
contentValues = new ContentValues();
contentValues.put("name", "newName");
contentValues.put("phone", "456);
contentResolver.update(uri, contentValues, null, null);
(3)删除数据:
ContentResolver contentResolver = getContentResolver();
Uriuri = Uri.parse("content://com.example.myProvider/student/1");
contentResolver.delete(uri, null, null);
(4)查找数据:
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.myProvider/student");
Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
}
cursor.close();
(5)监听数据变化:
以插入数据时监听数据变化为例:
第一:在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册此URI上的访问者:
case MATCH_ONE_CODE:
id = db.insert("student", null, values);
String path = uri.toString();
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id);
第二:使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:
private class StudentContentObserver extends ContentObserver
{
public StudentContentObserver(Handler handler)
{
super(handler);
}
// 得到数据的变化通知
@Override
public void onChange(boolean selfChange)
{
Log.d("xxx", "change");
Toast.makeText(MainActivity.this, "数据发生变化", Toast.LENGTH_LONG).show();
}
}
contentResolver = getContentResolver(); contentResolver.registerContentObserver(Uri.parse("content://com.example.myProvider/student"), true, new StudentContentObserver(new Handler()));
6.主要代码:
MyProvider.java:
public class MyProvider extends ContentProvider{
private StudentOpenHelper helper;
private static final String AUTHORITY = "com.example.myProvider";
private static final int MATCH_ALL_CODE = 200;
private static final int MATCH_ONE_CODE = 201;
private static UriMatcher uriMatcher;
// 数据集的MIME类型字符串以vnd.android.cursor.dir/开头
public static final String PERSONS_TYPE = "vnd.android.cursor.dir/vnd.com.example.myProvider.student";
// 单一数据的MIME类型字符串以vnd.android.cursor.item/开头
public static final String PERSONS_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.example.myProvider.student";
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "student", MATCH_ALL_CODE);
uriMatcher.addURI(AUTHORITY, "student/#", MATCH_ONE_CODE);
}
@Override
public boolean onCreate() {
helper = new StudentOpenHelper(getContext());
return true;
}
@Nullable
@Override//查找
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase db = helper.getReadableDatabase();
int flag = uriMatcher.match(uri);
switch (flag){
case MATCH_ALL_CODE:
return db.query("student", projection, selection, selectionArgs, null, null, null);
case MATCH_ONE_CODE:
long id = ContentUris.parseId(uri);
String where = "id=" + id;
where += !TextUtils.isEmpty(selection) ? "and("+selection+")" : "";
return db.query("student", projection, where, selectionArgs, null, null, null);
default:
throw new IllegalArgumentException("Unknown URI:" + uri);
}
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)) {
case MATCH_ALL_CODE:
return PERSONS_TYPE;
case MATCH_ONE_CODE:
return PERSONS_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Nullable
@Override//插入
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
int flag = uriMatcher.match(uri);
long id = 0;
switch (flag){
case MATCH_ALL_CODE:
id = db.insert("student", null, values);
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, id);
case MATCH_ONE_CODE:
id = db.insert("student", null, values);
String path = uri.toString();
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id);
default:
throw new IllegalArgumentException("Unknown URI:"+uri);
}
}
@Override//删除
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int flag = uriMatcher.match(uri);
int count = 0;
switch(flag){
case MATCH_ALL_CODE:
count = db.delete("student", selection, selectionArgs);
break;
case MATCH_ONE_CODE:
long id = ContentUris.parseId(uri);
String where = "id=" + id;
where += !TextUtils.isEmpty(selection) ? "and(" + selection +")" : "";
count = db.delete("student", where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI:"+uri);
}
return count;
}
@Override//更新
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int flag = uriMatcher.match(uri);
int count = 0;
switch(flag){
case MATCH_ALL_CODE:
count = db.update("student", values, selection, selectionArgs);
break;
case MATCH_ONE_CODE:
long id = ContentUris.parseId(uri);
String where = "id=" + id;
where += !TextUtils.isEmpty(selection) ? "and(" + selection +")" : "";
count = db.update("student", values, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI:"+uri);
}
return count;
}
}
MainActivity.java:
public class MainActivity extends Activity implements View.OnClickListener{
private Button insert_btn;
private Button query_btn;
private Button update_btn;
private Button delete_btn;
private ListView listView;
private MyAdapter adapter;
private EditText name_et;
private EditText phone_et;
ContentResolver contentResolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView(){
insert_btn = (Button) this.findViewById(R.id.insert_btn);
query_btn = (Button) this.findViewById(R.id.query_btn);
update_btn = (Button) this.findViewById(R.id.update_btn);
delete_btn = (Button) this.findViewById(R.id.delete_btn);
insert_btn.setOnClickListener(this);
query_btn.setOnClickListener(this);
update_btn.setOnClickListener(this);
delete_btn.setOnClickListener(this);
name_et = (EditText) this.findViewById(R.id.name_et);
phone_et = (EditText) this.findViewById(R.id.phone_et);
listView = (ListView) this.findViewById(R.id.listView);
adapter = new MyAdapter(this, getStudents());
listView.setAdapter(adapter);
}
private class StudentContentObserver extends ContentObserver
{
public StudentContentObserver(Handler handler)
{
super(handler);
}
// 得到数据的变化通知
@Override
public void onChange(boolean selfChange)
{
Toast.makeText(MainActivity.this, "数据发生变化", Toast.LENGTH_LONG).show();
}
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.insert_btn://在表中插入数据
contentResolver = getContentResolver();
//注册监听
contentResolver.registerContentObserver(Uri.parse("content://com.example.myProvider/student"), true, new StudentContentObserver(new Handler()));
Uri uri = Uri.parse("content://com.example.myProvider/student");
ContentValues contentValues = new ContentValues();
contentValues.put("name", name_et.getText().toString());
contentValues.put("phone", phone_et.getText().toString());
Uri newUri = contentResolver.insert(uri, contentValues);
adapter.setStudents(getStudents());
adapter.notifyDataSetChanged();
break;
case R.id.update_btn://更新id为1的数据
contentResolver = getContentResolver();
uri = Uri.parse("content://com.example.myProvider/student/1");
contentValues = new ContentValues();
contentValues.put("name", name_et.getText().toString());
contentValues.put("phone", phone_et.getText().toString());
contentResolver.update(uri, contentValues, null, null);
adapter.setStudents(getStudents());
adapter.notifyDataSetChanged();
break;
case R.id.query_btn://查询数据
adapter.setStudents(getStudents());
adapter.notifyDataSetChanged();
break;
case R.id.delete_btn://删除id为1的数据
contentResolver = getContentResolver();
uri = Uri.parse("content://com.example.myProvider/student/1");
contentResolver.delete(uri, null, null);
adapter.setStudents(getStudents());
adapter.notifyDataSetChanged();
break;
}
}
/**
* 查询数据库,获取student表中数据集合
* @return
*/
private List<Student> getStudents(){
List<Student> students = new ArrayList<>();
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.myProvider/student");
Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");
while(cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Student student = new Student(id, name, phone);
students.add(student);
}
cursor.close();
return students;
}
}
demo效果:
完整demo请点击这里。
参考文档:
https://developer.android.com/guide/topics/providers/content-provider-creating.html?hl=zh-cn
http://www.cnblogs.com/gaopeng527/p/4591750.html
http://www.jianshu.com/p/d5d5b68c3acb
http://www.cnblogs.com/linjiqin/archive/2011/05/28/2061396.html