作用:暴露应用的数据。可以获取不同应用的数据。
/data/data/应用包/databases/xxx.db
2.创建一个类继承Provider
Provider自身方法: onCreate query insert delete update getType --- 必须要重写
Provider要访问本应用数据库,需要在Provider中创建一个SQLiteOpenHelper,并且在onCreate方法中实例化。
然后再每个要执行数据库操作方法中(query insert delete update)通过helper打开数据库并使用数据库相应方法。
Cursor query(...) 查询返回值为Cursor,即查询内容都在Cursor中
Uri insert(...) 返回新添加数据的uri
int update(...) 返回更新操作影响的行数
int delete(...) 返回删除操作影响的行数
其原理就是在Provider中保存一个SQLiteOpneHelper,通过helper得到SQLiteDatabase。
然后在其增删改查的方法中,调用database的相应的增删改查方法。
3.在清单中注册
四大组件之一,要注册。
注册时,需要类名与权限(android:authorities),权限即为对外暴露的访问该提供者的标示
当应用程序启动,会自动创建内容提供者。
4.访问内容提供者,使用ContentResolver
ContentResolver resolver = getContentResolver();
Resolver方法:query insert delete update
5.Uri
1)Uri格式:content://主机名或authority/路径(路径中可包含ID)
content://com.itheima/person/1
Uri.parse("uri...")
注意:操作ID要使用类ContentUris,见后。
2)安卓自身的Uri以及表字段,都有对应的常量。
联系人Uri常量:Calls.CONTENT_URI;
联系人通话记录表中字段Calls.NUMBER --- 电话号码,Calls.DURATION --- 通话时长, Calls._ID --- ID号。
多媒体Uri常量:(andrdroid.provider.MediaStore.Audio.)Media.EXTERNAL_CONTENT_URI --- 访问音频外部存储的Uri
(andrdroid.provider.MediaStore.Audio.)Media.INTERNAL_CONTENT_URI --- 访问音频手机内存的Uri
(android.provider.MediaStore.Images.)Media.EXTERNAL_CONTENT_URI / Media.INTERNAL_CONTENT_URI 图像
(android.provider.MediaStore.Video.)Media.EXTERNAL_CONTENT_URI / Media.INTERNAL_CONTENT_URI 视频
多媒体表字段: Media._ID; ID号 Media.DISPLAY_NAME 名称 Media.SIZE 大小
6.在内容提供者里面定义一组Uri
UriMatcher
方法:addURI(authority, path, code);
如:
matcher.addURI(authority, path, code);
参数:
authority即为清单中provider的authority
code为匹配码,即该uri对应的唯一码,matcher.match(uri)的返回值
matcher.addURI(authority, "m", 1000);
matcher.addURI(authority, "m/#", 1000);
注:#代表数字, *代表字符
代码:
class MyProvider extends ContentProvider{
//authority即为清单中注册的authority
private static final String authority = "...";
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static{
matcher.addURI(authority, "...", code);
}
}
match方法
7.ContentUris
该类用于获取Uri路径后面的ID部分,也可以为Uri路径加上ID部分。
添加ID -- withAppendId()
Uri uri = Uri.parse("content://....");
Uri resultUri = ContentUris.withAppendId(uri, 10);
获取ID -- parseId()
Uri uri = Uri.parse("content://..../10");
long personId = ContentUris.parseId(uri);
示例:一个应用访问另一个应用的数据库。
Provider应用
public class MyProvider extends ContentProvider {
private MyOpenHelper helper;
private static final int MM = 10;
private static final int MM_ID = 100;
// 表名
private String table = "mm";
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
// 与清单provider的authority一致
private static String authority = "yp";
static {
// content://yp/mm
matcher.addURI(authority, "mm", MM);
// content://yp/mm/1
matcher.addURI(authority, "mm/#", MM_ID);
}
@Override
public boolean onCreate() {
helper = MyOpenHelper.getInstance(getContext());
return false;
}
/**
* 查询
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = helper.getReadableDatabase();
// 获得uri匹配码
int code = matcher.match(uri);
Cursor cursor = null;
// 通过判断匹配码,根据不同的uri做不同的操作
switch (code) {
// uri中没有带指定的id
case MM:
// select * form mm where name = xxx
cursor = db.query(table, new String[] { "*" }, selection,
selectionArgs, null, null, null);
break;
// uri中带有指定的id
case MM_ID:
// 获取指定的id
long id = ContentUris.parseId(uri);
// 判断对方是否包含查询条件
if (selection == null) {
// 如果不包含查询条件
selection = "_id = ?";
selectionArgs = new String[] { id + "" };
} else {
// 如果包含查询条件,将id条件拼接
// select * from mm where name = xxx and id = xx
selection = selection + " and _id = " + id;
}
cursor = db.query(table, new String[] { "*" }, selection,
selectionArgs, null, null, null);
break;
default:
break;
}
// 数据库不可以关闭
return cursor;
}
/**
* 插入
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
long id = db.insert(table, "_id", values);
return ContentUris.withAppendedId(uri, id);
}
/**
* 更新
*/
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = helper.getReadableDatabase();
// 获得uri匹配码
int code = matcher.match(uri);
int rows = 0;
// 通过判断匹配码,根据不同的uri做不同的操作
switch (code) {
// uri中没有带指定的id
case MM:
rows = db.update(table, values, selection, selectionArgs);
break;
// uri中带有指定的id
case MM_ID:
// 获取指定的id
long id = ContentUris.parseId(uri);
// 判断对方是否包含查询条件
if (selection == null) {
// 如果不包含查询条件
selection = "_id = ?";
selectionArgs = new String[] { id + "" };
} else {
// 如果包含查询条件,将id条件拼接
selection = selection + " and _id = " + id;
}
rows = db.update(table, values, selection, selectionArgs);
break;
default:
break;
}
return rows;
}
/**
* 删除
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getReadableDatabase();
// 获得uri匹配码
int code = matcher.match(uri);
int ret = 0;
// 通过判断匹配码,根据不同的uri做不同的操作
switch (code) {
// uri中没有带指定的id
case MM:
db.delete(table, selection, selectionArgs);
break;
// uri中带有指定的id
case MM_ID:
// 获取指定的id
long id = ContentUris.parseId(uri);
// 判断对方是否包含查询条件
if (selection == null) {
// 如果不包含查询条件
selection = "_id = ?";
selectionArgs = new String[] { id + "" };
} else {
// 如果包含查询条件,将id条件拼接
selection = selection + " and _id = " + id;
}
ret = db.delete(table, selection, selectionArgs);
break;
default:
break;
}
return ret;
}
@Override
public String getType(Uri uri) {
return null;
}
}
Resolver应用
public class MainActivity extends Activity {
private ContentResolver resolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resolver = getContentResolver();
}
public void click(View v) {
ContentValues values = new ContentValues();
switch (v.getId()) {
case R.id.insert:
values.clear();
values.put("name", "ly");
values.put("age", 20);
resolver.insert(Uri.parse("content://yp/mm"), values);
break;
case R.id.update:
values.clear();
values.put("name", "yl");
values.put("age", 18);
resolver.update(Uri.parse("content://yp/mm/10"), values, null, null);
break;
case R.id.delete:
resolver.delete(Uri.parse("content://yp/mm"), "name = ?",
new String[] { "yl" });
break;
case R.id.query:
Cursor cursor = resolver.query(Uri.parse("content://yp/mm"),
new String[] { "*" }, null, null, null);
while (cursor.moveToNext()) {
int _id = cursor.getInt(0);
String name = cursor.getString(1);
int age = cursor.getInt(2);
System.out.println("_id = " + _id + " name = " + name
+ " age = " + age);
}
cursor.close();
break;
default:
break;
}
}
}
8.UriMatcher与ContentUris
UriMatcher.match()方法与ContentUris.withAppendId/parseId方法区别。
一条uri: "content://ly/mm/10"
使用UriMatcher.addURI()方法:matcher.addURI(authority, "mm", 100); 是将这条URI独一无二的分配100标识码。即后面使用matcher.match(uri);的返回值如果是100,那么当前uri就是 "content://ly/mm/10"。
而ContentUris操作的是uri最后的 '10' ,即向uri最后插入数字或者获取uri最后的数字。
9.ContentObserver
内容观察者,观察内容提供者数据的变化。如果内容提供者数据变化了,那么发送信息给观察者。
原理:在resolver身上注册一个观察者observer,当数据改变时,调用观察者的onChange方法
在provider的数据会发生改变的方法中调用resolver的notifyChange方法。
1) 在Provider中数据改变要通知的某方法内(如insert)
getContext().getContentProvider().nofityChange(uri, observer);
例:getContext().getContentProvider().nofityChange(uri, null);
2) 在数据改变时需要被通知的类中,写一个内部类继承ContentObserver。
并实现构造方法和onChange(boolean selfChange)方法。数据发生改变时,onChange方法被调用
3) 在该类中注册观察者
resolver.registerContentObserver(uri, notifyForDescendents, observer);
第二个参数为boolean类型的值,表示是否级联。
如:uri为 content://yp/mm 那么content://yp/mm/10发生变化时是否通知。
例:resolver.registerContentObserver(uri, false, observer);
Provider
/**
* 插入
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
//数据改变时发出通知
getContext().getContentResolver().notifyChange(uri, null);
SQLiteDatabase db = helper.getWritableDatabase();
long id = db.insert(table, "_id", values);
return ContentUris.withAppendedId(uri, id);
}
LApp
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
MyObserver observer = new MyObserver(new Handler());
// 注册观察者
resolver.registerContentObserver(Uri.parse("content://yp/mm"), false,
observer);
System.out.println("内容观察者已经注册");
}
private class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
System.out.println("数据已经发生改变!!!");
}
}
}