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的簡單使用啦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM