android菜鸟学习笔记22----ContentProvider(二)ContentObserver的简单使用

现在有这样一个应用A通过ContentProvider提供自己的数据给其他应用,应用B通过ContentResolver获取应用A中提供的数据,并将其展示在ListView中,而应用C通过ContentResolver修改应用A中的数据,或者添加新的数据。现在的问题是应用C修改A中数据后,应用B的ListView中显示的还是历史数据……

具体程序如下:

ContentProvider和插入数据的应用分别复用上一篇中的两个应用,然后新建一个应用,用于获取ContentProvider中的数据,并在一个ListView中展示:

布局文件activity _main.xml中添加一个ListView:

1 <ListView
2
3         android:id="@+id/lv"
4
5         android:layout_width="match_parent"
6
7         android:layout_height="wrap_content"></ListView>

布局文件item_layout.xml用于显示ListView中的条目:

 1 <?xml version="1.0" encoding="utf-8"?>
 2
 3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 4
 5     android:layout_width="match_parent"
 6
 7     android:layout_height="match_parent"
 8
 9     android:orientation="horizontal" >
10
11     <TextView
12
13         android:id="@+id/tv_id"
14
15         android:layout_width="wrap_content"
16
17         android:layout_height="wrap_content"
18
19         android:layout_weight="1"/>
20
21     <TextView
22
23         android:id="@+id/tv_name"
24
25         android:layout_width="wrap_content"
26
27         android:layout_height="wrap_content"
28
29         android:layout_weight="1"/>
30
31     <TextView
32
33         android:id="@+id/tv_gender"
34
35         android:layout_width="wrap_content"
36
37         android:layout_height="wrap_content"
38
39         android:layout_weight="1"/>
40
41     <TextView
42
43         android:id="@+id/tv_age"
44
45         android:layout_width="wrap_content"
46
47         android:layout_height="wrap_content"
48
49         android:layout_weight="1"/>
50 </LinearLayout>

MainActivity添加获取数据并显示到ListView的代码:

 1 protected void onCreate(Bundle savedInstanceState) {
 2
 3         super.onCreate(savedInstanceState);
 4
 5         setContentView(R.layout.activity_main);
 6
 7         uri = Uri.parse("content://cn.csc.content_provider/t_student");
 8
 9         Cursor cursor = getContentResolver().query(uri, new String[]{"id as _id","name","gender","age"}, null, null, null);
10
11         lv = (ListView) findViewById(R.id.lv);
12
13         lv.setAdapter(new SimpleCursorAdapter(this,R.layout.item_layout,cursor,
14
15                    new String[]{"_id","name","gender","age"},new int[]{R.id.tv_id,R.id.tv_name,R.id.tv_gender,R.id.tv_age}));
16
17 }

运行结果:

上面使用到了SimpleCursorAdapter这个Adapter类,其构造的参数说明:

第一个参数指明应用上下文实例

第二个参数指明ListView中每个条目显示的布局id

第三个参数指明存放要显示数据的Cursor结果集对象

第四和第五个参数共同指明Cursor结果集中每一个字段放在布局文件中的那个控件中,这两个数组中的元素时按顺序一一对应的。第四个参数是String[]类型的,每个元素为结果集中的字段名,第五个参数时int[]类型的,每个参数时布局文件中每个控件的资源id。

在这里需要特别注意的一点是,SimpleCursorAdapter要求表中必须存在名为_id的字段,否则会报错,从而停止正常运行。

但是我之前所建立的表中并没有_id字段,id字段倒是有一个,但是又不想去改变表的定义,这时,就可以在query()方法中,用于指定要查询的字段的第二个参数中使用别名:如上面的写法是:

Cursor cursor = getContentResolver().query(uri, new String[]{"id as _id","name","gender","age"}, null, null, null);

这样结果集中的字段名就由id变为了_id,SimpleCursorAdapter就能正常使用了。

但是,此时由充当应用C角色的应用通过insert()方法添加数据,当前应用中的ListView并没有变化,还是显示不完整的历史数据!!!

针对这个问题,android提供了一个名为ContentObserver的类,用于观察特定uri的数据有无变化,有变化时,则可以根据自己需要做相应的处理。

ContentObserver的使用:

第一步:在应用B中注册ContentObserver,声明要观察的uri,并重写其onChange方法完成需要的业务逻辑

具体代码如下:

 1 uri = Uri.parse("content://cn.csc.content_provider/t_student");
 2
 3 getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {
 4
 5                @Override
 6
 7                public void onChange(boolean selfChange) {
 8
 9                      // TODO Auto-generated method stub
10
11                      super.onChange(selfChange);
12
13                      Log.i("Test","changed");
14
15                      Cursor cursor = getContentResolver().query(uri, new String[]{"id as _id","name","gender","age"}, null, null, null);
16
17                   lv = (ListView) findViewById(R.id.lv);
18
19                   lv.setAdapter(new SimpleCursorAdapter(MainActivity.this,R.layout.item_layout,cursor,
20
21                              new String[]{"_id","name","gender","age"},new int[]{R.id.tv_id,R.id.tv_name,R.id.tv_gender,R.id.tv_age}));
22
23                   Toast.makeText(MainActivity.this, "数据有变化,已然刷新ListView显示", Toast.LENGTH_SHORT).show();
24
25                }
26
27
28
29           });

第二步:在应用A中的insert()、update()、delete()方法中,通知观察这些uri的内容观察者,告知数据发生变化,会触发其对应的onChange方法,完成数据变化的业务。

具体代码如下:

1 getContext().getContentResolver().notifyChange(uri, null);

当前ListView状态:

在应用C中测试增删改方法,观察应用B中的运行:

增:

 1 public void testInsert(){
 2
 3            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student");
 4
 5            ContentValues values = new ContentValues();
 6
 7            values.put("name", "csc");
 8
 9            values.put("gender", "male");
10
11            values.put("age", 25);
12
13            Uri uri2 = getContext().getContentResolver().insert(uri, values);
14
15            Log.i("Test",uri2.toString());
16
17 }

运行结果:

删:

1 public void testDelete(){
2
3            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student");
4
5            int i = getContext().getContentResolver().delete(uri, "id>?", new String[]{"7"});
6
7            Log.i("Test",i+"");
8
9 }

运行结果:

改:

 1 public void testUpdate(){
 2
 3            Uri uri = Uri.parse("content://cn.csc.content_provider/t_student");
 4
 5            ContentValues values = new ContentValues();
 6
 7            values.put("name", "dqrcsc");
 8
 9            values.put("gender", "male");
10
11            values.put("age", 24);
12
13            int i = getContext().getContentResolver().update(uri, values, "id>?", new String[]{"3"});
14
15            Log.i("Test",i+"");
16
17 }

运行结果:

以上,就是ContentObserver的简单使用啦。

时间: 2024-08-11 09:48:01

android菜鸟学习笔记22----ContentProvider(二)ContentObserver的简单使用的相关文章

android菜鸟学习笔记7----android布局(二)

3.FrameLayout:帧布局 如同Flash或者photoshop中图层的概念,在上面的图层遮盖下面的图层,没被遮到的地方仍然显示出来. 右击res/layout,然后在弹出的菜单中选择new,然后选择Android Xml File,要新建FrameLayout布局文件,就选择FrameLayout作为其根节点即可.文件名为frame_layout.xml. 代码如下: 1 <?xml version="1.0" encoding="utf-8"?&g

android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据

主要是基于HTTP协议与服务端进行交互. 涉及到的类和接口有:URL.HttpURLConnection.HttpClient等 URL: 使用一个String类型的url构造一个URL对象,如: URL url = new URL(http://10.0.2.2/index.php); openConnection()方法返回一个对指定url的资源的连接.返回类型是URLConnection,但是,由于这里我们一般用的是http协议,所以返回的实际是HttpURLConnection对象,故一

android菜鸟学习笔记7----Activity(一)

Activity是android应用程序中重要的组件之一,常听到的android四大组件是Activity.Service.BroadcastReceiver和ContentProvider.它间接继承自android.content.Context,因此,有些时候都直接把Activity实例当做Context的实例来使用. 如前面所提到的要在应用程序中使用Activity,必须在Android Manifest.xml中配置它. 新建一个Android工程,新建过程中勾选create acti

android菜鸟学习笔记14----Android控件(三) ListView的简单使用

MVC模式: MVC的基本原理就是通过Controller连接View和Model.当View中所显示的数据发生变化时,会通知Controller,然后由Controller调用Model中的相关方法执行相应的数据修改操作.反之,当Model中的数据发生变化时,也会通知Controller,由Controller通知View更新显示内容.如此一来,就使得数据部分与视图部分相分离,任何一方发生改变都不会影响到另一方. 而在android中,MVC的一个常见应用就是ListView显示数据.V代表的

android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人

要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上找对应ContentProvider的源码:https://github.com/android 有好多个,哪一个才是短信数据的ContentProvider呢? 在filters输入框:输入telephony. 现在只有一个了,打开: 装有git的话,可以选择clone到本地,没有的话,就选择下载

android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用

ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentProvider. 多个应用共享数据时,如何区分是哪个应用中的那部分数据呢? ContentProvider通过Uri标识具体某个应用的某些数据.当一个应用提供了ContentProvider向其他应用共享数据时,该应用在其ContentProvider中添加标识自己特定数据的Uri,然后其他应用想要获得

android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据

补充:关于PHP服务端可能出现的问题: 如果你刚好也像我一样,用php实现的服务端程序,采用的是apache服务器,那么虚拟主机的配置可能会影响到android应用的调试!! 在android应用中访问的IP都是10.0.2.2,如果在apache虚拟主机配置文件中配置了多个虚拟主机,那么将默认解析为对第一个虚拟主机的请求,所以,在调试android应用时,应该将对应的服务端所配置的那个虚拟主机放在配置文件中的第一个虚拟主机的位置.否则就会出现请求的文件不存在等的错误. 服务端返回JSON数据及

android菜鸟学习笔记8----Activity(二)

关于Activity的生命周期: 下面是Activity整个生命周期中,状态发生变化时所回调的方法,它们对应着Activity完整的生命过程. void  onCreate(Bundle savedInstanceState):Activity被创建时回调 void  onStart()  :在onCreate()或者onRestart()之后被调用,即Activity第一次创建或者从不可见变为可见状态时调用. void  onResume()  :恢复到活动状态时回到,在onStart()之后

android菜鸟学习笔记31----Android使用百度地图API(二)获取地理位置及地图控制器的简单使用

1.获取当前地理位置: Android中提供了一个LocationManager的类,用于管理地理位置.不能通过构造函数获取该类的实例,而是通过Context的getSystemService(): LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 该类中有几个比较常用的方法: getLastKnownLocation(String provider)用于根据传入的provider