(1)能使用ContentProvider共享数据
(2)能使用内容观察者观察其他程序的数据变化
设计一个监测数据库的工程,要求:
创建工程,设计界面和功能,完成项目的调试,并将程序的代码和运行结果记录下来。
实验设备:Windows+Android Studio
1.不是右键New-Other-Content Provider来生成内容观察者,导致AndroidManifest.xml没有注册。
错误提示:INSTALL_FAILED_CONFLICTING_PROVIDER
2.Android java.lang.SecurityException: Failed to find provider异常说明
这是因为安卓8.0以上有了权限管理,本代码比较老,我还没有解决,可以参考一下,如果用8.0以下的版本应该可以运行。(1条消息) Android java.lang.SecurityException: Failed to find provider异常说明_hellopeng1的博客-CSDN博客_failed to find provider
创建名为ContentObserverDB程序,指定包名为cn.itcast.contenobserverdb。
设置背景图片。背景可自己在drawable修改
放置4个Button控件,分别显示“添加”、“更新”、“删除”、“查询”。背景可自己在drawable修改
代码如下
package cn.itcast.contentobserverdb;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class PersonDBOpenHelper extends SQLiteOpenHelper {//构造方法,调用该方法创建一个person.db数据库public PersonDBOpenHelper(Context context) {super(context, "person.db", null, 1);}@Overridepublic void onCreate(SQLiteDatabase db) {//创建该数据库的同时新建一个info表,表中有_id,name这两个字段db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20))");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
需要右键选择New-Other-Content Provider,即在AndroidManifest.xml注册好,代码如下。
package cn.itcast.contentobserverdb;
//省略导包
public class PersonProvider extends ContentProvider {//定义一个uri路径的匹配器,如果路径匹配不成功返回-1private static UriMatcher mUriMatcher = new UriMatcher(-1);private static final int SUCCESS = 1; //匹配路径成功时的返回码private PersonDBOpenHelper helper; //数据库操作类的对象//添加路径匹配器的规则static {mUriMatcher.addURI("cn.itcast.contentobserverdb", "info", SUCCESS);}@Overridepublic boolean onCreate() { //当内容提供者被创建时调用helper = new PersonDBOpenHelper(getContext());return false;}/*** 查询数据操作*/@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {//匹配查询的Uri路径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("路径不正确,无法查询数据!");}}/*** 添加数据操作*/@Overridepublic 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("路径不正确,无法插入数据!");}}/*** 删除数据操作*/@Overridepublic 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("路径不正确,无法随便删除数据!");}}/*** 更新数据操作*/@Overridepublic 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("路径不正确,无法更新数据!");}}@Overridepublic String getType(Uri uri) {return null;}
}
6.编写界面代码MainActivity.java
package cn.itcast.contentobserverdb;
//省略导包
public class MainActivity extends AppCompatActivity implementsView.OnClickListener {private ContentResolver resolver;private Uri uri;private ContentValues values;private Button btnInsert;private Button btnUpdate;private Button btnDelete;private Button btnSelect;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView(); //初始化界面createDB(); //创建数据库}private void initView() {btnInsert = findViewById(R.id.btn_insert);btnUpdate = findViewById(R.id.btn_update);btnDelete = findViewById(R.id.btn_delete);btnSelect = 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();}@Overridepublic void onClick(View v) {//得到一个内容提供者的解析对象resolver = getContentResolver();//获取一个Uri路径uri = Uri.parse("content://cn.itcast.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
新建一个工程,创建一个名为MonitorData的程序,不用设置其界面。代码如下。
package cn.itcast.monitordata;
//省略导包
public class MainActivity extends AppCompatActivity {@Overrideprotected 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);}}@Overrideprotected void onDestroy() {super.onDestroy();//取消注册内容观察者getContentResolver().unregisterContentObserver(new MyObserver(new Handler()));}




内容观察者(ContentObserver)是用来观察指定Uri所代表的数据。当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发ContentObserver的onChange()方法。此时在onChange()方法里使用ContentResovler可以查询到变化的数据。