内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API,通过ContentResolver类可以访问ContentProvider中共享的数据。
ContentProvider的工作原理如下:
ContentResolver提供一系列增删改查的方法对数据进行操作,并且这些方法以Uri的形式对外提供数据。
Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path。
在程序包名处点击右键选择【New】—【Other】—【Content Provider】选项
输入内容提供者的Class Name(名称)和URI Authorities(唯一标识,通常使用包名)
内容提供者创建完成后,Android Studio会自动在AndroidManifest.xml中对内容提供者进行注册。
<application ......>
......
<provider
android:name=".MyContentProvider"
android:authorities="cn.itcast.mycontentprovider"
android:enabled="true"
android:exported="true" >
</provider>
</application>
内容观察者(ContentObserver)是用来观察指定Uri
所代表的数据的,当ContentObserver
观察到指定Uri代表的数据发生变化时,就会触发onChange()
方法,在该方法中使用ContentResovler
可以查询到变化的数据。
要使用ContentObserver
观察数据变化,就必须在ContentProvider
的delete()
、insert()
、update()
方法中调用ContentResolver
的notifyChange()
方法。
ContentObserver的两个常用方法:
public void ContentObserver(Handler handler) : ContentObserver的派生类都需要调用该构造方法。参数可以是主线程Handler,也可以是任何Handler对象(Handler将在第9章讲解)。
public void onChange(boolean selfChange) : 当观察的Uri代表的数据发生变化时,会触发该方法。在该方法中使用ContentResovler可以查询到变化的数据。
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://aaa.bbb.ccc");
resolver.registerContentObserver(uri, true, new MyObserver(new Handler()));
private class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Uri uri = Uri.parse("content://aaa.bbb.ccc");//会监测该Uri的数据变化情况
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { "address", "date", "type", "body" }, null, null, null);
// ......
cursor.close();
}
}
public class PersonDBOpenHelper extends SQLiteOpenHelper {
//构造方法,调用此方法新建一个person.db的数据库并返回一个数据库帮助类的对象
public PersonDBOpenHelper(Context context) {
super(context, "person.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建该数据库的同时新建一个info表,表中有_id,name这两个字段
db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20))");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
PersonProvider:内容提供者,向外部提供对数据库表info表的增删改查
public class PersonProvider extends ContentProvider {
//定义一个uri路径的匹配器,如果路径匹配不成功返回 -1
private static UriMatcher mUriMatcher = new UriMatcher(-1);
//匹配路径成功时的返回码
private static final int SUCCESS = 1;
//数据库操作类的对象
private PersonDBOpenHelper helper;
//添加路径匹配器的规则
static {
mUriMatcher.addURI("com.example.week13_01.contentobserverdb", "info", SUCCESS);
}
public PersonProvider() {
}
@Override
public boolean onCreate() {
helper = new PersonDBOpenHelper(getContext());
return false;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
SQLiteDatabase db = helper.getWritableDatabase();
int count = db.delete("info", selection, selectionArgs);
//提示数据库的内容变化了
if (count > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
db.close();
return count;
} else {
throw new IllegalArgumentException("路径不正确,我是不会让你随便删除数据的!");
}
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
SQLiteDatabase db = helper.getReadableDatabase();
long rowId = db.insert("info", null, values);
if (rowId > 0) {
Uri insertedUri = ContentUris.withAppendedId(uri, rowId);
//提示数据库的内容变化了
getContext().getContentResolver().notifyChange(insertedUri, null);
return insertedUri;
}
db.close();
return uri;
} else {
throw new IllegalArgumentException("路径不正确,我是不会给你插入数据的!");
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
//匹配查询路径
int code = mUriMatcher.match(uri);
if (code == SUCCESS){
SQLiteDatabase db = helper.getReadableDatabase();
return db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
}else{
throw new IllegalArgumentException("路径不正确,我是不会给你提供数据的!");
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
SQLiteDatabase db = helper.getWritableDatabase();
int count = db.update("info", values, selection, selectionArgs);
//提示数据库的内容变化了
if (count > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
db.close();
return count;
} else {
throw new IllegalArgumentException("路径不正确,我是不会让你更新数据的!");
}
}
}
resolver : 内容消费者,调用内容
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ContentResolver resolver;
private Uri uri;
private ContentValues values;
private Button btnInsert;
private Button btnUpdate;
private Button btnDelete;
private Button btnSelect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化界面
createDB();//创建数据库
}
private void initView() {
btnInsert = (Button) findViewById(R.id.btn_insert);
btnUpdate = (Button) findViewById(R.id.btn_update);
btnDelete = (Button) findViewById(R.id.btn_delete);
btnSelect = (Button) findViewById(R.id.btn_select);
btnInsert.setOnClickListener(this);
btnUpdate.setOnClickListener(this);
btnDelete.setOnClickListener(this);
btnSelect.setOnClickListener(this);
}
private void createDB() {
//创建数据库并向info表中添加3条数据
PersonDBOpenHelper helper = new PersonDBOpenHelper(this);
SQLiteDatabase db = helper.getWritableDatabase();
for (int i = 0; i < 3; i++) {
ContentValues values = new ContentValues();
values.put("name", "itcast" + i);
db.insert("info", null, values);
}
db.close();
}
@Override
public void onClick(View v) {
//得到一个内容提供者的解析对象
resolver = getContentResolver();
//新加一个uri路径,参数是string类型的
uri = Uri.parse("content://com.example.week13_01.contentobserverdb/info");
//新建一个ContentValues对象,该对象以key-values的形式来添加记录到数据库表中
values = new ContentValues();
switch (v.getId()) {
case R.id.btn_insert:
Random random = new Random();
values.put("name", "add_itcast" + random.nextInt(10));
Uri newuri = resolver.insert(uri, values);
Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
Log.i("数据库应用:", "添加");
break;
case R.id.btn_delete:
//返回删除数据的条目数
int deleteCount = resolver.delete(uri, "name=?",
new String[]{"itcast0"});
Toast.makeText(this, "成功删除了" + deleteCount + "行",
Toast.LENGTH_SHORT).show();
Log.i("数据库应用:", "删除");
break;
case R.id.btn_select:
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
//返回查询结果,是一个指向结果集的游标
Cursor cursor = resolver.query(uri, new String[]{"_id", "name"},
null, null, null);
//遍历结果集中的数据,将每一条遍历的结果存储在一个List的集合中
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
map.put("_id", cursor.getString(0));
map.put("name", cursor.getString(1));
data.add(map);
}
//关闭游标,释放资源
cursor.close();
Log.i("数据库应用:", "查询结果:" + data.toString());
break;
case R.id.btn_update:
//将数据库info表中name为itcast1的这条记录更改为name是update_itcast
values.put("name", "update_itcast");
int updateCount = resolver.update(uri, values, "name=?",
new String[]{"itcast1"});
Toast.makeText(this, "成功更新了" + updateCount + "行",
Toast.LENGTH_SHORT).show();
Log.i("数据库应用:", "更新");
break;
}
}
}
新建一个模块:monitor,检测者
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 该uri路径指向数据库应用中的数据库info表
Uri uri = Uri.parse("content://cn.itcast.contentobserverdb/info");
//注册内容观察者,参数uri指向要监测的数据库info表,
//参数true定义了监测的范围,最后一个参数是一个内容观察者对象
getContentResolver().registerContentObserver(uri, true,
new MyObserver(new Handler()));
}
private class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {//handler 是一个消息处理器。
super(handler);
}
@Override
//当info表中的数据发生变化时则执行该方法
public void onChange(boolean selfChange) {
Log.i("监测数据变化", "有人动了你的数据库!");
super.onChange(selfChange);
}
}
}