标签:
内容提供者是Android中的四大组件之一,可以将应用中的数据对外进行共享
内容提供者将数据的访问方式统一,不必针对不同数据类型采取不同的访问策略
内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据
内容提供者中数据更改可被监听
定义类继承ContentProvider,根据需要重写内部方法
在清单文件的<application>节点下进行配置,<provider>标签中需要指定name和authorities属性
name为类名,包名从程序Package开始,以“.”开始
authorities:是访问Provider时的路径,要唯一
URI代表要操作的数据,由scheme、authorites、path三部分组成
content://cn.itcast.provider.itcast/person
scheme:固定为content,代表访问内容提供者
authorites:<provider>节点中的authorites属性
path:程序定义的路径,可根据业务逻辑定义
Ÿ 当程序调用CRUD方法时会传入Uri
Ÿ 我们通过Uri判断调用者要操作的数据
可以使用工具类UriMatcher来判断Uri
addURI方法可以添加Uri
match方法可以匹配一个Uri判断其类型
Ÿ 根据业务逻辑操作数据
Ÿ 如果返回数据是单条数据:vnd.android.cursor.item
Ÿ 如果返回数据是多条数据:vnd.android.cursor.dir
public class PersonProvider extends android.content.ContentProvider {
private static final int PERSON = 0;
private static final int PERSON_ID = 1;
private UriMatcher matcher;
private DBOpenHelper helper;
@Override
public boolean onCreate() {
matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI("com.demo.sqlite.provider", "person", PERSON); // 添加一个可以匹配的Uri
matcher.addURI("com.demo.sqlite.provider", "person/#", PERSON_ID);
helper = new DBOpenHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (matcher.match(uri)) { // 对Uri进行匹配
case PERSON_ID:
String idSelection = "id = " + ContentUris.parseId(uri); // Converts the last path segment to a long.
// 注意此处字符串拼装
selection = selection == null ? idSelection : idSelection + " AND " + selection;
case PERSON:
SQLiteDatabase db = helper.getReadableDatabase();
return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (matcher.match(uri)) {
case PERSON:
SQLiteDatabase db = helper.getWritableDatabase();
long id = db.insert("person", null, values); // 使用 db.insert() 方法插入数据,返回 id
// 而 db.exceSQL(sql)方式插入数据,返回 void
// return Uri.parse("content://com.demo.sqlite.provider/person/" + id); // 与下句效果相同
return ContentUris.withAppendedId(uri, id); // Appends the given ID to the end of the path.
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (matcher.match(uri)) {
case PERSON_ID:
long id = ContentUris.parseId(uri);
selection = selection == null ? "id = " + id : "id = " +id + " AND " +selection;
case PERSON:
SQLiteDatabase db = helper.getWritableDatabase();
// return : The number of rows affected
return db.delete("person", selection, selectionArgs);
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
switch (matcher.match(uri)) {
case PERSON_ID:
long id = ContentUris.parseId(uri);
selection = selection == null ? "id = " + id : "id = " + id + " AND " + selection;
case PERSON:
SQLiteDatabase db = helper.getWritableDatabase();
// @return the number of rows affected
return db.update("person", values, selection, selectionArgs);
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
@Override
public String getType(Uri uri) {
switch (matcher.match(uri)) {
case PERSON_ID:
return "vnd.android.cursor.item/person";
case PERSON:
return "vnd.android.cursor.dir/person";
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
Ÿ 通过Context获得ContentResolver对象
Ÿ 调用ContentResolver对象的方法即可访问内容提供者
private static final String TAG = "ProviderTest";
// 查询 id = 36
public void testQuery1() {
// 通过 ContentResolver 调用 ContentProvider 提供的方法
ContentResolver resolver = getContext().getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
Cursor c = resolver.query(uri, new String[] { "id", "name", "balance" }, "id = ?", new String[] { "36" }, null);
if (c.moveToNext()) {
Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));
Logger.i(TAG, person.toString());
}
}
// 查询所有 person
public void testQuery2() {
// 通过 ContentResolver 调用 ContentProvider 提供的方法
ContentResolver resolver = getContext().getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
Cursor c = resolver.query(uri, null, null, null, null);
while (c.moveToNext()) {
Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));
Logger.i(TAG, person.toString());
}
}
// 通过附带 id 查询 person
public void testQuery3() {
// 通过 ContentResolver 调用 ContentProvider 提供的方法
ContentResolver resolver = getContext().getContentResolver();
// Uri
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/55");
Cursor c = resolver.query(uri, null, "name = ?", new String[] { "Ashia_54" }, null);
while (c.moveToNext()) {
Person person = new Person(c.getInt(0), c.getString(1), c.getInt(2));
Logger.i(TAG, person.toString());
}
}
public void testInsert() {
ContentResolver resolver = getContext().getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
ContentValues values = new ContentValues();
Person person = new Person("another Person uri insert", 7000);
values.put("name", person.getName());
values.put("balance", person.getBalance());
Uri reUri = resolver.insert(uri, values);
Cursor c = resolver.query(reUri, null, null, null, null);
if (c.moveToNext()) {
Person rePerson = new Person(c.getInt(0), c.getString(1), c.getInt(2));
Logger.i(TAG, rePerson.toString());
}
}
public void testDelete() {
// ContentResolver :This class provides applications access to the content model.
ContentResolver resolver = getContext().getContentResolver();
Uri url = Uri.parse("content://com.demo.sqlite.provider/person/121");
// 忘记加 = ?, 异常如下
// android.database.sqlite.SQLiteException: bind or column index out of range
long id = resolver.delete(url, "name = ?", new String[] {"zhangsan"});
Logger.i(TAG, id + "");
id = resolver.delete(url, null, null);
Logger.i(TAG, id + "");
}
public void testDeleteAll() {
ContentResolver resolver = getContext().getContentResolver();
Uri url = Uri.parse("content://com.demo.sqlite.provider/person");
int deleteNum = resolver.delete(url, null, null);
Logger.i(TAG, deleteNum + "");
}
public void testUpdate() {
ContentResolver resolver = getContext().getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/122");
ContentValues values = new ContentValues();
values.put("balance", 8000);
int update = resolver.update(uri, values, "balance = ?", new String[] {"9000"});
Logger.i(TAG, update + "");
}
public void testUpdateById() {
ContentResolver resolver = getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "new name");
values.put("balance", 7000);
values.put("id", 2);
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/123");
int update = resolver.update(uri, values, null, null);
Logger.i(TAG, update + "");
}
// Uri写错,异常
// java.lang.IllegalArgumentException: Unknown URI
// 主键 id 重复,异常
// android.database.sqlite.SQLiteConstraintException
public void testGetType() {
ContentResolver resolver = getContext().getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person/1");
Logger.i(TAG, resolver.getType(uri));
uri = Uri.parse("content://com.demo.sqlite.provider/person");
Logger.i(TAG, resolver.getType(uri));
}
Ÿ 在内容提供者中可以通知其他程序数据发生变化
通过Context的getContentResolver()方法获取ContentResolver
调用其notifyChange()方法发送数据修改通知
Ÿ 在其他程序中可以通过ContentObserver监听数据变化
通过Context的getContentResolver()方法获取ContentResolver
调用其registerContentObserver()方法指定对某个Uri注册ContentObserver
自定义ContentObserver,重写onChange()方法获取数据
发送数据修改通知
public Uri insert(Uri uri, ContentValues values) {
switch (matcher.match(uri)) {
case PERSON:
SQLiteDatabase db = helper.getWritableDatabase();
long id = db.insert("person", null, values);
// Notify registered observers that a row was updated. 注册 observer
// @param observer The observer that originated the change, may be null
// 产生改变的Observer. 此处为Provider带来的改变,传 null
this.getContext().getContentResolver().notifyChange(uri, null); // 发送修改通知
// return Uri.parse("content://com.demo.sqlite.provider/person/" + id);
return ContentUris.withAppendedId(uri, id);
default:
throw new IllegalArgumentException("No Match Uri " + uri);
}
}
定义一个ContentObserver,监听Uri所对应的内容提供者的变化
protected static final String TAG = "ObserverActivity";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 定义一个ContentObserver
ContentObserver observer = new ContentObserver(new Handler()) {
/**
* Returns true if this observer is interested in notifications for
* changes made through the cursor the observer is registered with.
*/
// 是否传递自己的改变
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
/**
* This method is called when a change occurs to the cursor that is
* being observed.
*
* @param selfChange
* true if the update was caused by a call to commit on
* the cursor that is being observed.
*/
// 当被监听的内容发生了改变时,调用该方法
@Override
public void onChange(boolean selfChange) {
Logger.i(TAG, "监听到了变化");
// 打印出最后插入的信息
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
// SELECT * FROM person ORDER BY id DESC LIMIT 1;
Cursor c = resolver.query(uri, null, null, null, "id DESC LIMIT 1");
if(c.moveToNext()) {
String result = "id = " + c.getInt(0) + ", name = " + c.getString(1) + ", balance = " + c.getInt(2);
Logger.i(TAG, result);
Toast.makeText(ObserverActivity.this, result, 1).show();
}
// 父类未做任何实现
super.onChange(selfChange);
}
};
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
// 注册一个ContentObserver
/*
* @param notifyForDescendents
* If true changes to URIs beginning with uri will also cause notifications to be sent.
* Iffalse only changes to the exact URI specified by uri will cause notifications to be sent.
* If true, than any URI values at or below the specified URI will also trigger a match.
*/
// 是否监听以 "uri" 开头 的其他 uri
getContentResolver().registerContentObserver(uri, true, observer);
}
通过ContentObserver,监测内容改变,自动更新ListView
bt_insert = (Button) findViewById(R.id.bt_insert);
bt_insert.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ContentResolver resolver = ListViewSimpleCursorAdapterActivity.this.getContentResolver();
Uri url = Uri.parse("content://com.demo.sqlite.provider/person");
ContentValues values = new ContentValues();
values.put("name", "test name");
values.put("balance", 3000);
resolver.insert(url, values);
}
});
lv_person.setOnItemClickListener(new MyOnItemClickListener());
Uri uri = Uri.parse("content://com.demo.sqlite.provider/person");
getContentResolver().registerContentObserver(uri, false, new MyContentObserver(new Handler()));
public class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
// 当所监听的内容发生了改变,则更新lv中的数据
Cursor c = new PersonDAO(ListViewSimpleCursorAdapterActivity.this).queryAllCursor();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(ListViewSimpleCursorAdapterActivity.this, //
R.layout.listview_item, //
c, //
new String[] { "_id", "name", "balance" }, //
new int[] { R.id.tv_id, R.id.tv_name, R.id.tv_balance });
lv_person.setAdapter(adapter);
lv_person.setOnItemClickListener(new MyOnItemClickListener());
super.onChange(selfChange);
Logger.i(TAG, "onChange");
}
}
错误
Uri写错,异常 java.lang.IllegalArgumentException: Unknown URI
主键 id 重复,异常 android.database.sqlite.SQLiteConstraintException
测试ListView更新时,界面总是自动关闭
如果自己是内容提供者,也是内容观察者,
在测试用例中更改内容,应用会强制退出
标签:
原文地址:http://www.cnblogs.com/youyu16/p/4383339.html