Android——使用ContentProvider共享数据
创始人
2024-03-02 08:18:06

实验名称: 使用ContentProvider共享数据                                                

实验目的:

(1)能使用ContentProvider共享数据

(2)能使用内容观察者观察其他程序的数据变化

实验内容及原理:

设计一个监测数据库的工程,要求:

  1. 能够操作数据库的数据 
  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

实验步骤:

1.创建ContentObserverDB程序

创建名为ContentObserverDB程序,指定包名为cn.itcast.contenobserverdb。

2.导入界面图片

设置背景图片。背景可自己在drawable修改

3.放置按钮控件

放置4个Button控件,分别显示“添加”、“更新”、“删除”、“查询”。背景可自己在drawable修改


4.创建数据库PersonDBOpenHelper.java

代码如下

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) {}
}

5.创建内容提供者PersonProvider.java

需要右键选择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> data = new ArrayList>();//返回查询结果,是一个指向结果集的游标Cursor cursor = resolver.query(uri, new String[]{"_id", "name"},null, null, null);//遍历结果集中的数据,将每一条遍历的结果存储在一个List的集合中while (cursor.moveToNext()) {Map map = new HashMap();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_itcastvalues.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;}}
}

7.创建MonitorData程序

新建一个工程,创建一个名为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()));}

实验结果与分析:

程序界面运行结果:

    

访问数据库info数据:

响应结果:

内容观察者响应结果:

问题及思考:

简述内容观察者的工作原理。

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

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...