ContentObserver的使用完整詳細示例


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package cn.testcontentprovider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
  * Demo描述:
  * 自定義ContentProvider的實現
  * ContentProvider主要用於在不同的應用程序之間共享數據,這也是官方推薦的方式.
  *
  * 注意事項:
  * 1 在AndroidManifest.xml中注冊ContentProvider時的屬性
  *   android:exported=true表示允許其他應用訪問.
  * 2 注意*和#這兩個符號在Uri中的作用
  *   其中*表示匹配任意長度的字符
  *   其中#表示匹配任意長度的數據
  *   所以:
  *   一個能匹配所有表的Uri可以寫成:
  *   一個能匹配person表中任意一行的Uri可以寫成:
  *  
  */
public class ContentProviderTest extends ContentProvider {
     private SQLiteDatabaseOpenHelper mSQLiteDatabaseOpenHelper;
     private final static String  AUTHORITY=cn.bs.testcontentprovider;
     private  static UriMatcher mUriMatcher;
     private static final int PERSON_DIR = 0 ;
     private static final int PERSON = 1 ;
     
     /**
      * 利用靜態代碼塊初始化UriMatcher
      * 在UriMatcher中包含了多個Uri,每個Uri代表一種操作
      * 當調用UriMatcher.match(Uri uri)方法時就會返回該uri對應的code;
      * 比如此處的PERSONS和PERSON
      */
     static {
         mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
         // 該URI表示返回所有的person,其中PERSONS為該特定Uri的標識碼
         mUriMatcher.addURI(AUTHORITY, person, PERSON_DIR);
         // 該URI表示返回某一個person,其中PERSON為該特定Uri的標識碼
         mUriMatcher.addURI(AUTHORITY, person/#, PERSON);
     }
     
     
     /**
      * 在自定義ContentProvider中必須覆寫getType(Uri uri)方法.
      * 該方法用於獲取Uri對象所對應的MIME類型.
      *
      * 一個Uri對應的MIME字符串遵守以下三點:
      * 1  必須以vnd開頭
      * 2  如果該Uri對應的數據可能包含多條記錄,那么返回字符串應該以vnd.android.cursor.dir/開頭
      * 3  如果該Uri對應的數據只包含一條記錄,那么返回字符串應該以vnd.android.cursor.item/開頭
      */
     @Override
     public String getType(Uri uri) {
         switch (mUriMatcher.match(uri)) {
         case PERSON_DIR:
             return vnd.android.cursor.dir/+AUTHORITY+.persons;
         case PERSON:
             return vnd.android.cursor.item/+AUTHORITY+.person;
         default :
             throw new IllegalArgumentException(unknown uri+uri.toString());
         }
     }  
 
     
     @Override
     public boolean onCreate() {
         mSQLiteDatabaseOpenHelper= new SQLiteDatabaseOpenHelper(getContext());
         return true ;
     }
     
 
     /**
      * 插入操作:
      * 插入操作只有一種可能:向一張表中插入
      * 返回結果為新增記錄對應的Uri
      * 方法db.insert()返回結果為新增記錄對應的主鍵值
      */
     @Override
     public Uri insert(Uri uri, ContentValues values) {
         SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
         switch (mUriMatcher.match(uri)) {
         case PERSON_DIR:
             long newId = db.insert(person, name,phone,salary, values);
             //向外界通知該ContentProvider里的數據發生了變化 ,以便ContentObserver作出相應
             getContext().getContentResolver().notifyChange(uri, null ); 
             return ContentUris.withAppendedId(uri, newId);
         default :
             throw new IllegalArgumentException(unknown uri + uri.toString());
         }
     }
     
     /**
      * 更新操作:
      * 更新操作有兩種可能:更新一張表或者更新某條數據
      * 在更新某條數據時原理類似於查詢某條數據,見下.
      */
     @Override
     public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
         SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
         int updatedNum = 0 ;
         switch (mUriMatcher.match(uri)) {
         // 更新表
         case PERSON_DIR:
             updatedNum = db.update(person, values, selection, selectionArgs);
             break ;
         // 按照id更新某條數據
         case PERSON:
             long id = ContentUris.parseId(uri);
             String where = personid= + id;
             if (selection != null && !.equals(selection.trim())) {
                 where = selection +  and  + where;
             }
             updatedNum = db.update(person, values, where, selectionArgs);
             break ;
         default :
             throw new IllegalArgumentException(unknown uri + uri.toString());
         }
         //向外界通知該ContentProvider里的數據發生了變化 ,以便ContentObserver作出相應
         getContext().getContentResolver().notifyChange(uri, null ); 
         return updatedNum;
     }
     
     /**
      * 刪除操作:
      * 刪除操作有兩種可能:刪除一張表或者刪除某條數據
      * 在刪除某條數據時原理類似於查詢某條數據,見下.
      */
     @Override
     public int delete(Uri uri, String selection, String[] selectionArgs) {
         SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
         int deletedNum = 0 ;
         switch (mUriMatcher.match(uri)) {
         // 刪除表
         case PERSON_DIR:
             deletedNum = db.delete(person, selection, selectionArgs);
             break ;
         // 按照id刪除某條數據
         case PERSON:
             long id = ContentUris.parseId(uri);
             String where = personid= + id;
             if (selection != null && !.equals(selection.trim())) {
                 where = selection +  and  + where;
             }
             deletedNum = db.delete(person, where, selectionArgs);
             break ;
         default :
             throw new IllegalArgumentException(unknown uri + uri.toString());
         }
         //向外界通知該ContentProvider里的數據發生了變化 ,以便ContentObserver作出相應
         getContext().getContentResolver().notifyChange(uri, null ); 
         return deletedNum;
     }
 
     /**
      * 查詢操作:
      * 查詢操作有兩種可能:查詢一張表或者查詢某條數據
      *
      * 注意事項:
      * 在查詢某條數據時要注意--因為此處是按照personid來查詢
      * 某條數據,但是同時可能還有其他限制.例如:
      * 要求personid為2且name為xiaoming1
      * 所以在查詢時分為兩步:
      * 第一步:
      * 解析出personid放入where查詢條件
      * 第二步:
      * 判斷是否有其他限制(如name),若有則將其組拼到where查詢條件.
      *
      * 詳細代碼見下.
      */
     @Override
     public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
         SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
         Cursor cursor = null ;
         switch (mUriMatcher.match(uri)) {
         // 查詢表
         case PERSON_DIR:
             cursor = db.query(person, projection, selection, selectionArgs, null , null , sortOrder);
             break ;
         // 按照id查詢某條數據
         case PERSON:
             // 第一步:
             long id = ContentUris.parseId(uri);
             String where = personid= + id;
             // 第二步:
             if (selection != null && !.equals(selection.trim())) {
                 where = selection +  and  + where;
             }
             cursor = db.query(person, projection, where, selectionArgs, null , null , sortOrder);
             break ;
         default :
             throw new IllegalArgumentException(unknown uri + uri.toString());
         }
         return cursor;
     }
     
 
}


SQLiteDatabaseOpenHelper如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.testcontentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteDatabaseOpenHelper extends SQLiteOpenHelper {
     public SQLiteDatabaseOpenHelper(Context context) {
         super (context, contentprovidertest.db, null , 1 );
     }
 
     @Override
     public void onCreate(SQLiteDatabase db) {
         db.execSQL(create table person(personid integer primary key autoincrement,name varchar( 20 ),phone varchar( 12 ),salary  Integer( 12 )));    
     }
 
     //當數據庫版本號發生變化時調用該方法
     @Override
     public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
         //db.execSQL(ALTER TABLE person ADD phone varchar(12) NULL);
         //db.execSQL(ALTER TABLE person ADD salary  Integer NULL);
     }
 
}


MainActivity如下:

?
1
2
3
4
5
6
7
8
9
10
11
package cn.testcontentprovider;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
     }
 
}


AndroidManifest.xml如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--?xml version= 1.0 encoding=utf- 8 ?-->
<manifest android:versioncode= "1" android:versionname= "1.0" package = "cn.testcontentprovider" xmlns:android= "http://schemas.android.com/apk/res/android" >
 
     <uses-sdk android:minsdkversion= "8" android:targetsdkversion= "8" >
 
     <uses-permission android:name= "android.permission.INTERNET" >
     <uses-permission android:name= "android.permission.ACCESS_NETWORK_STATE" >
     <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" >
     <uses-permission android:name= "android.permission.MOUNT_UNMOUNT_FILESYSTEMS" >
     
     
         
             <intent-filter>
                 
 
                 <category android:name= "android.intent.category.LAUNCHER" >
             </category></action></intent-filter>
         </activity>
         
          <provider android:authorities= "cn.bs.testcontentprovider" android:exported= "true" android:name= "cn.testcontentprovider.ContentProviderTest" >
     </provider></application>
 
</uses-permission></uses-permission></uses-permission></uses-permission></uses-sdk></manifest>

 

 


main.xml如下:

?
1
<relativelayout android:layout_height= "match_parent" android:layout_width= "match_parent" xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http://schemas.android.com/tools" ><button android:layout_centerinparent= "true" android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "該應用包含一個自定義的ContentProvider" android:textsize= "15sp" ></button></relativelayout>



 

 

以下代碼為工程TestBaidu

 

MainActivity如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package cn.testbaidu;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
/**
  * Demo描述:
  * 應用A(TestBaidu)調用另外一個應用(TestContentProvider)中的自定義ContentProvider,即:
  * 1 自定義ContentProvider的使用
  * 2 其它應用調用該ContentProvider
  * 3 ContentObserver的使用
  *
  * 備注說明:
  * 1 該例子在以前版本的基礎上整理了代碼
  * 2 該例子在以前版本的基礎上融合了ContentObserver的使用
  *   利用ContentObserver隨時監聽ContentProvider的數據變化.
  *   為實現該功能需要在自定義的ContentProvider的insert(),update(),delete()
  *   方法中調用getContext().getContentResolver().notifyChange(uri, null);
  *   向外界通知該ContentProvider里的數據發生了變化 ,以便ContentObserver作出相應 
  *
  * 測試方法:
  * 1 依次測試ContentProvider的增查刪改(注意該順序)!!
  * 2 其它應用查詢該ContentProvider的數據
  *
  */
public class MainActivity extends Activity {
     private Button mAddButton;
     private Button mDeleteButton;
     private Button mUpdateButton;
     private Button mQueryButton;
     private Button mTypeButton;
     private long lastTime= 0 ;
     private ContentResolver mContentResolver;
     private ContentObserverSubClass mContentObserverSubClass;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         init();
         initContentObserver();
     }
 
     private void init() {
         mContentResolver= this .getContentResolver();
         
         mAddButton=(Button) findViewById(R.id.addButton);
         mAddButton.setOnClickListener( new ClickListenerImpl());
         
         mDeleteButton=(Button) findViewById(R.id.deleteButton);
         mDeleteButton.setOnClickListener( new ClickListenerImpl());
         
         mUpdateButton=(Button) findViewById(R.id.updateButton);
         mUpdateButton.setOnClickListener( new ClickListenerImpl());
         
         mQueryButton=(Button) findViewById(R.id.queryButton);
         mQueryButton.setOnClickListener( new ClickListenerImpl());
         
         mTypeButton=(Button) findViewById(R.id.typeButton);
         mTypeButton.setOnClickListener( new ClickListenerImpl());
         
     }
     
     
 
     // 注冊一個針對ContentProvider的ContentObserver用來觀察內容提供者的數據變化
     private void initContentObserver() {
         Uri uri = Uri.parse(content: //cn.bs.testcontentprovider/person);
         mContentObserverSubClass= new ContentObserverSubClass( new Handler());
         this .getContentResolver().registerContentObserver(uri, true ,mContentObserverSubClass);
     }
     
     @Override
     protected void onDestroy() {
         super .onDestroy();
         if (mContentObserverSubClass!= null ) {
             this .getContentResolver().unregisterContentObserver(mContentObserverSubClass);
         }
     }
 
     
     
     
     // 自定義一個內容觀察者ContentObserver
     private class ContentObserverSubClass extends ContentObserver {
 
         public ContentObserverSubClass(Handler handler) {
             super (handler);
         }
 
         //采用時間戳避免多次調用onChange( )
         @Override
         public void onChange( boolean selfChange) {
             super .onChange(selfChange);
             System.out.println(ContentObserver onChange() selfChange=+ selfChange);
             if (System.currentTimeMillis()-lastTime> 2000 ) {
                 ContentResolver resolver = getContentResolver();
                 Uri uri = Uri.parse(content: //cn.bs.testcontentprovider/person);
                 // 獲取最新的一條數據
                 Cursor cursor = resolver.query(uri, null , null , null ,personid desc limit 1 );
                 while (cursor.moveToNext()) {
                     int personid = cursor.getInt(cursor.getColumnIndex(personid));
                     System.out.println(內容提供者中的數據發生變化,現數據中第一條數據的personid=+ personid);
                 }
                 cursor.close();
                 lastTime=System.currentTimeMillis();
             } else {
                 System.out.println(時間間隔過短,忽略此次更新);
             }
             
             
         }
         
         @Override
         public boolean deliverSelfNotifications() {
             return true ;
         }
         
     }
     
     
     
     
 
     private class ClickListenerImpl implements OnClickListener {
         @Override
         public void onClick(View v) {
             switch (v.getId()) {
             case R.id.addButton:
                 Person person = null ;
                 for ( int i = 0 ; i < 5 ; i++) {
                     person = new Person(xiaoming + i, 9527 + i, ( 8888 + i));
                     testInsert(person);
                 }
                 break ;
             case R.id.deleteButton:
                 testDelete( 1 );
                 break ;
             case R.id.updateButton:
                 testUpdate( 3 );
                 break ;
             case R.id.queryButton:
                 // 查詢表
                 // queryFromContentProvider(-1);
 
                 // 查詢personid=2的數據
                 testQuery( 2 );
                 break ;
             case R.id.typeButton:
                 testType();
                 break ;
             default :
                 break ;
             }
 
         }
 
     }
     private void testInsert(Person person) {
         ContentValues contentValues= new ContentValues();
         contentValues.put(name, person.getName());
         contentValues.put(phone, person.getPhone());
         contentValues.put(salary,person.getSalary());
         Uri insertUri=Uri.parse(content: //cn.bs.testcontentprovider/person);
         Uri returnUri=mContentResolver.insert(insertUri, contentValues);
         System.out.println(新增數據:returnUri=+returnUri);
     }
     
     private void testDelete( int index){
         Uri uri=Uri.parse(content: //cn.bs.testcontentprovider/person/+String.valueOf(index));
         mContentResolver.delete(uri, null , null );
     }
     
     private void testUpdate( int index){
         Uri uri=Uri.parse(content: //cn.bs.testcontentprovider/person/+String.valueOf(index));
         ContentValues values= new ContentValues();
         values.put(name, hanmeimei);
         values.put(phone, 1234 );
         values.put(salary, 333 );
         mContentResolver.update(uri, values, null , null );
     }
 
     private void testQuery( int index) {
         Uri uri= null ;
         if (index<= 0 ) {
             //查詢表
             uri=Uri.parse(content: //cn.bs.testcontentprovider/person);
         } else {
              //按照id查詢某條數據
             uri=Uri.parse(content: //cn.bs.testcontentprovider/person/+String.valueOf(index));
         }
         
         //對應上面的:查詢表
         //Cursor cursor= mContentResolver.query(uri, null, null, null, null);
         
         //對應上面的:查詢personid=2的數據
         //注意:因為name是varchar字段的,所以應該寫作name='xiaoming1'
         //     若寫成name=xiaoming1查詢時會報錯
         Cursor cursor= mContentResolver.query(uri, null , name= 'xiaoming1' , null , null );
         
         while (cursor.moveToNext()){
             int personid=cursor.getInt(cursor.getColumnIndex(personid));
             String name=cursor.getString(cursor.getColumnIndex(name));
             String phone=cursor.getString(cursor.getColumnIndex(phone));
             int salary=cursor.getInt(cursor.getColumnIndex(salary));
             System.out.println(查詢得到:personid= + personid+,name=+name+,phone=+phone+,salary=+salary);
         }
         cursor.close();
     }
     
     private void testType(){
         Uri dirUri=Uri.parse(content: //cn.bs.testcontentprovider/person);
         String dirType=mContentResolver.getType(dirUri);
         System.out.println(dirType:+dirType);
         
         Uri itemUri=Uri.parse(content: //cn.bs.testcontentprovider/person/3);
         String itemType=mContentResolver.getType(itemUri);
         System.out.println(itemType:+itemType);
     }
 
}



 

Person如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package cn.testbaidu;
 
public class Person {
     private Integer id;
     private String name;
     private String phone;
     private Integer salary;
     public Person(String name, String phone,Integer salary) {
         this .name = name;
         this .phone = phone;
         this .salary=salary;
     }
     public Person(Integer id, String name, String phone,Integer salary) {
         this .id = id;
         this .name = name;
         this .phone = phone;
         this .salary=salary;
     }
     public Integer getId() {
         return id;
     }
     public void setId(Integer id) {
         this .id = id;
     }
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this .name = name;
     }
     public String getPhone() {
         return phone;
     }
     public void setPhone(String phone) {
         this .phone = phone;
     }
     public Integer getSalary() {
         return salary;
     }
     public void setSalary(Integer salary) {
         this .salary = salary;
     }
     @Override
     public String toString() {
         return Person [id= + id + , name= + name + , phone= + phone+ , salary= + salary + ];
     }
     
     
     
}


免責聲明!

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



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