1、相關ContentProvider概念解析: html
一、ContentProvider簡介
在Android官方指出的Android的數據存儲方式總共有五種,分別是:Shared Preferences、網絡存儲、文件存儲、外儲存儲、SQLite。可是咱們知道通常這些存儲都只是在單獨的一個應用程序之中達到一個數據的共享,有時候咱們須要操做其餘應用程序的一些數據,例如咱們須要操做系統裏的媒體庫、通信錄等,這時咱們就可能經過ContentProvider來知足咱們的需求了。 java
二、爲何要選擇ContentProvider? android
ContentProvider向咱們提供了咱們在應用程序以前共享數據的一種機制,而咱們知道每個應用程序都是運行在不一樣的應用程序的,數據和文件在不一樣應用程序之間達到數據的共享不是沒有可能,而是顯得比較複雜,而正好Android中的ContentProvider則達到了這一需求,好比有時候咱們須要操做手機裏的聯繫人,手機裏的多媒體等一些信息,咱們均可以用到這個ContentProvider來達到咱們所需。 sql
1)、ContentProvider爲存儲和獲取數據提供了統一的接口。ContentProvide對數據進行封裝,不用關心數據存儲的細節。使用表的形式來組織數據。
2)、使用ContentProvider能夠在不一樣的應用程序之間共享數據。
3)、Android爲常見的一些數據提供了默認的ContentProvider(包括音頻、視頻、圖片和通信錄等)。
總的來講使用ContentProvider對外共享數據的好處是統一了數據的訪問方式。 數據庫
三、Uri介紹 網絡
爲系統的每個資源給其一個名字,比方說通話記錄。
1)、每個ContentProvider都擁有一個公共的URI,這個URI用於表示這個ContentProvider所提供的數據。
2)、Android所提供的ContentProvider都存放在android.provider包中。 將其分爲A,B,C,D 4個部分:
A:標準前綴,用來講明一個Content Provider控制這些數據,沒法改變的;"content://"
B:URI 的標識,用於惟一標識這個ContentProvider,外部調用者能夠根據這個標識來找到它。它定義了是哪一個Content Provider提供這些數據。對於第三方應用程序,爲了保證URI標識的惟一性,它必須是一個完整的、小寫的類名。這個標識在 元素的 authorities屬性中說明:通常是定義該ContentProvider的包.類的名稱
C:路徑(path),通俗的講就是你要操做的數據庫中表的名字,或者你也能夠本身定義,記得在使用的時候保持一致就能夠了;"content://com.bing.provider.myprovider/tablename"
D:若是URI中包含表示須要獲取的記錄的ID;則就返回該id對應的數據,若是沒有ID,就表示返回所有; "content://com.bing.provider.myprovider/tablename/#" #表示數據id。 app
PS: dom
路徑(path)能夠用來表示咱們要操做的數據,路徑的構建應根據業務而定,以下:
一、要操做person表中id爲10的記錄,能夠構建這樣的路徑:/person/10
二、要操做person表中id爲10的記錄的name字段, person/10/name
三、要操做person表中的全部記錄,能夠構建這樣的路徑:/person
四、要操做xxx表中的記錄,能夠構建這樣的路徑:/xxx
五、固然要操做的數據不必定來自數據庫,也能夠是文件、xml或網絡等其餘存儲方式,以下:
要操做xml文件中person節點下的name節點,能夠構建這樣的路徑:/person/name
六、若是要把一個字符串轉換成Uri,可使用Uri類中的parse()方法,以下:Uri uri = Uri.parse("content://com.bing.provider.personprovider/person") ide
四、UriMatcher類使用介紹 函數
由於Uri表明了要操做的數據,因此咱們常常須要解析Uri,並從Uri中獲取數據。Android系統提供了兩個用於操做Uri的工具類,分別爲UriMatcher和ContentUris 。掌握它們的使用,會便於咱們的開發工做。
UriMatcher類用於匹配Uri,它的用法以下:
首先第一步把你須要匹配Uri路徑所有給註冊上,以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
UriMatcher sMatcher =newUriMatcher(UriMatcher.NO_MATCH);
//若是match()方法匹配
content://com.bing.procvide.personprovider/person路徑,返回匹配碼爲1
sMatcher.addURI("com.bing.procvide.personprovider","person",1);//添加須要匹配uri,若是匹配就會返回匹配碼
//若是match()方法匹配
content://com.bing.provider.personprovider/person/230路徑,返回匹配碼爲2
sMatcher.addURI("com.bing.provider.personprovider","person/#",2);//#號爲通配符
switch(sMatcher.match(Uri.parse("
content://com.ljq.provider.personprovider/person/10"))) {
case1
break;
case2
break;
default://不匹配
break;
}
|
五、ContentUris類使用介紹
ContentUris類用於操做Uri路徑後面的ID部分,它有兩個比較實用的方法:
withAppendedId(uri, id)用於爲路徑加上ID部分:
1
2
3
|
Uri uri = Uri.parse("
content://com.bing.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri,10);
|
1
2
|
Uri uri = Uri.parse("
content://com.ljq.provider.personprovider/person/10")
longpersonid = ContentUris.parseId(uri);//獲取的結果爲:10
|
1)ContentProvider類主要方法的做用:
public boolean onCreate():該方法在ContentProvider建立後就會被調用,Android開機後,ContentProvider在其它應用第一次訪問它時纔會被建立。
public Uri insert(Uri uri, ContentValues values):該方法用於供外部應用往ContentProvider添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs):該方法用於供外部應用從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用於供外部應用更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用於供外部應用從ContentProvider中獲取數據。
public String getType(Uri uri):該方法用於返回當前Url所表明數據的MIME類型。
2)若是操做的數據屬於集合類型,那麼MIME類型字符串應該以vnd.android.cursor.dir/開頭,
例如:要獲得全部person記錄的Uri爲content://com.bing.provider.personprovider/person,那麼返回的MIME類型字符串應該爲:"vnd.android.cursor.dir/person"。
3)若是要操做的數據屬於非集合類型數據,那麼MIME類型字符串應該以vnd.android.cursor.item/開頭,
例如:獲得id爲10的person記錄,Uri爲content://com.bing.provider.personprovider/person/10,那麼返回的MIME類型字符串爲:"vnd.android.cursor.item/person"。
七、ContentResolver操做ContentProvider中的數據
1)當外部應用須要對ContentProvider中的數據進行添加、刪除、修改和查詢操做時,可使用ContentResolver 類來完成,要獲取ContentResolver 對象,可使用Activity提供的getContentResolver()方法。
2)ContentResolver 類提供了與ContentProvider類相同簽名的四個方法:
public Uri insert(Uri uri, ContentValues values):該方法用於往ContentProvider添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs):該方法用於從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用於更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用於從ContentProvider中獲取數據。
這些方法的第一個參數爲Uri,表明要操做的ContentProvider和對其中的什麼數據進行操做,
其實和contentprovider裏面的方法是同樣的.他們所對應的數據,最終是會被傳到咱們在以前程序裏面定義的那個contentprovider類的方法,
假設給定的是:Uri.parse("content://com.bing.providers.personprovider/person/10"),那麼將會對主機名爲com.bing.providers.personprovider的ContentProvider進行操做,操做的數據爲person表中id爲10的記錄。
使用ContentResolver對ContentProvider中的數據進行添加、刪除、修改和查詢操做:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("
content://com.bing.provider.personprovider/person");
//添加一條記錄
ContentValues values =newContentValues();
values.put("name","bingxin");
values.put("age",25);
resolver.insert(uri, values);
//獲取person表中全部記錄
Cursor cursor = resolver.query(uri,null,null,null,"personid desc");
while(cursor.moveToNext()){
Log.i("ContentTest","personid="+ cursor.getInt(0)+",name="+ cursor.getString(1));
}
//把id爲1的記錄的name字段值更改新爲zhangsan
ContentValues updateValues =newContentValues();
updateValues.put("name","zhangsan");
Uri updateIdUri = ContentUris.withAppendedId(uri,2);
resolver.update(updateIdUri, updateValues,null,null);
//刪除id爲2的記錄
Uri deleteIdUri = ContentUris.withAppendedId(uri,2);
resolver.delete(deleteIdUri,null,null);
|
1
2
3
4
5
6
|
publicclassPersonContentProviderextendsContentProvider {
publicUri insert(Uri uri, ContentValues values) {
db.insert("person","personid", values);
getContext().getContentResolver().notifyChange(uri,null);
}
}
|
1
2
3
4
5
6
7
8
9
10
|
getContentResolver().registerContentObserver(Uri.parse("
content://com.ljq.providers.personprovider/person"),
true,newPersonObserver(newHandler()));
publicclassPersonObserverextendsContentObserver{
publicPersonObserver(Handler handler) {
super(handler);
}
publicvoidonChange(booleanselfChange) {
//此處能夠進行相應的業務處理
}
}
|
2、ContentProvider的實現過程
一、定義一個CONTENT_URI常量,提供了訪問ContentProvider的標識符。
1
|
publicstaticfinalUri CONTENT_URI = Uri.parse("
content://com.example.codelab.transportationprovider");
|
1
|
publicclassFirstContentProviderextendsContentProvider
|
1
2
3
4
5
6
|
publicstaticfinalUriMatcher uriMatcher;
static{
uriMatcher =newUriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(Book.AUTHORITY,"item", Book.ITEM);
uriMatcher.addURI(Book.AUTHORITY,"item/#", Book.ITEM_ID);
}
|
addURI()方法是用來增長其餘URI匹配路徑的,
第一個參數傳入標識ContentProvider的AUTHORITY字符串。
第二個參數傳入須要匹配的路徑,這裏的#號爲通配符,表明匹配任意數字,另外還能夠用*來匹配任意文本。
第三個參數必須傳入一個大於零的匹配碼,用於match()方法對相匹配的URI返回相對應的匹配碼。 例如:sMatcher.addURI(「com.test.provider.personprovider」, 「person」, 1);若是match()方法匹配content://com.test.provider.personprovider/person路徑,返回匹配碼爲1。
三、實現query,insert,update,delete,getType和onCreate方法。
四、在AndroidManifest.xml當中進行聲明。
1
|
<provider android:name="com.bj.FirstContentProvider"android:authorities="com.bj.firstcontentprovider"></provider>
|
3、實例
一、常量類
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
|
/**
* 提供ContentProvider對外的各類常量,當外部數據須要訪問的時候,就能夠參考這些常量操做數據。
*
@author HB
*
*/
publicclassContentData {
publicstaticfinalString AUTHORITY ="hb.android.contentProvider";
publicstaticfinalString DATABASE_NAME ="teacher.db";
//建立 數據庫的時候,都必須加上版本信息;而且必須大於4
publicstaticfinalintDATABASE_VERSION =4;
publicstaticfinalString USERS_TABLE_NAME ="teacher";
publicstaticfinalclassUserTableDataimplementsBaseColumns {
publicstaticfinalString TABLE_NAME ="teacher";
//Uri,外部程序須要訪問就是經過這個Uri訪問的,這個Uri必須的惟一的。
publicstaticfinalUri CONTENT_URI = Uri.parse("
content://"+ AUTHORITY +"/teacher");
// 數據集的MIME類型字符串則應該以vnd.android.cursor.dir/開頭
publicstaticfinalString CONTENT_TYPE ="vnd.android.cursor.dir/hb.android.teachers";
// 單一數據的MIME類型字符串應該以vnd.android.cursor.item/開頭
publicstaticfinalString CONTENT_TYPE_ITME ="vnd.android.cursor.item/hb.android.teacher";
/* 自定義匹配碼 */
publicstaticfinalintTEACHERS =1;
/* 自定義匹配碼 */
publicstaticfinalintTEACHER =2;
publicstaticfinalString TITLE ="title";
publicstaticfinalString NAME ="name";
publicstaticfinalString DATE_ADDED ="date_added";
publicstaticfinalString SEX ="SEX";
publicstaticfinalString DEFAULT_SORT_ORDER ="_id desc";
publicstaticfinalUriMatcher uriMatcher;
static{
// 常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
uriMatcher =newUriMatcher(UriMatcher.NO_MATCH);
// 若是match()方法匹配
content://hb.android.teacherProvider/teachern路徑,返回匹配碼爲TEACHERS
uriMatcher.addURI(ContentData.AUTHORITY,"teacher", TEACHERS);
// 若是match()方法匹配
content://hb.android.teacherProvider/teacher/230,路徑,返回匹配碼爲TEACHER
uriMatcher.addURI(ContentData.AUTHORITY,"teacher/#", TEACHER);
}
}
}
|
在建立UriMatcher對象uriMatcher時,咱們傳給構造函數的參數爲UriMatcher.NO_MATCH,它表示當uriMatcher不能匹配指定的URI時,就返回代碼UriMatcher.NO_MATCH。接下來增長了三個匹配規則,分別是uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(ContentData.AUTHORITY, "teacher", TEACHERS); uriMatcher.addURI(ContentData.AUTHORITY, "teacher/#", TEACHER);
它們的匹配碼分別是teacher.ITEM、teacher.ITEM_ID和teacher.ITEM_POS,其中,符號#表示匹配任何數字。
二、SQLite操做類DBOpenHelper
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
|
/**
* 這個類繼承SQLiteOpenHelper抽象類,用於建立數據庫和表。建立數據庫是調用它的父類構造方法建立。
*
@author HB
*/
publicclassDBOpenHelperextendsSQLiteOpenHelper {
// 在SQLiteOepnHelper的子類當中,必須有該構造函數,用來建立一個數據庫;
publicDBOpenHelper(Context context, String name, CursorFactory factory,
intversion) {
// 必須經過super調用父類當中的構造函數
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
// public DBOpenHelper(Context context, String name) {
// this(context, name, VERSION);
// }
publicDBOpenHelper(Context context, String name,intversion) {
this(context, name,null, version);
}
/**
* 只有當數據庫執行建立 的時候,纔會執行這個方法。若是更改表名,也不會建立,只有當建立數據庫的時候,纔會建立改表名以後 的數據表
*/
@Override
publicvoidonCreate(SQLiteDatabase db) {
System.out.println("create table");
db.execSQL("create table "+ ContentData.UserTableData.TABLE_NAME
+"("+ ContentData.UserTableData._ID
+" INTEGER PRIMARY KEY autoincrement,"
+ ContentData.UserTableData.NAME +" varchar(20),"
+ ContentData.UserTableData.TITLE +" varchar(20),"
+ ContentData.UserTableData.DATE_ADDED +" long,"
+ ContentData.UserTableData.SEX +" boolean)"+";");
}
@Override
publicvoidonUpgrade(SQLiteDatabase db,intoldVersion,intnewVersion) {
}
}
|
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
|
/**
* 這個類給外部程序提供訪問內部數據的一個接口
*
@author HB
*
*/
publicclassTeacherContentProviderextendsContentProvider {
privateDBOpenHelper dbOpenHelper =null;
// UriMatcher類用來匹配Uri,使用match()方法匹配路徑時返回匹配碼
/**
* 是一個回調函數,在ContentProvider建立的時候,就會運行,第二個參數爲指定數據庫名稱,若是不指定,就會找不到數據庫;
* 若是數據庫存在的狀況下是不會再建立一個數據庫的。(固然首次調用 在這裏也不會生成數據庫必須調用SQLiteDatabase的 getWritableDatabase,getReadableDatabase兩個方法中的一個纔會建立數據庫)
*/
@Override
publicbooleanonCreate() {
//這裏會調用 DBOpenHelper的構造函數建立一個數據庫;
dbOpenHelper =newDBOpenHelper(this.getContext(), ContentData.DATABASE_NAME, ContentData.DATABASE_VERSION);
returntrue;
}
/**
* 當執行這個方法的時候,若是沒有數據庫,他會建立,同時也會建立表,可是若是沒有表,下面在執行insert的時候就會出錯
* 這裏的插入數據也徹底能夠用sql語句書寫,而後調用 db.execSQL(sql)執行。
*/
@Override
publicUri insert(Uri uri, ContentValues values){
//得到一個可寫的數據庫引用,若是數據庫不存在,則根據onCreate的方法裏建立;
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
longid =0;
switch(uriMatcher.match(uri)) {
caseTEACHERS:
id = db.insert("teacher",null, values); // 返回的是記錄的行號,主鍵爲int,實際上就是主鍵值
returnContentUris.withAppendedId(uri, id);
caseTEACHER:
id = db.insert("teacher",null, values);
String path = uri.toString();
returnUri.parse(path.substring(0, path.lastIndexOf("/"))+id);// 替換掉id
default:
thrownewIllegalArgumentException("Unknown URI "+ uri);
}
}
@Override
publicintdelete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
intcount =0;
switch(uriMatcher.match(uri)) {
caseTEACHERS:
count = db.delete("teacher", selection, selectionArgs);
break;
caseTEACHER:
// 下面的方法用於從URI中解析出id,對這樣的路徑
content://hb.android.teacherProvider/teacher/10
// 進行解析,返回值爲10
longpersonid = ContentUris.parseId(uri);
String where ="_ID="+ personid; // 刪除指定id的記錄
where += !TextUtils.isEmpty(selection) ?" and ("+ selection +")":""; // 把其它條件附加上
count = db.delete("teacher", where, selectionArgs);
break;
default:
thrownewIllegalArgumentException("Unknown URI "+ uri);
}
db.close();
returncount;
}
@Override
publicintupdate(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
intcount =0;
switch(uriMatcher.match(uri)) {
caseTEACHERS:
count = db.update("teacher", values, selection, selectionArgs);
break;
caseTEACHER:
// 下面的方法用於從URI中解析出id,對這樣的路徑
content://com.ljq.provider.personprovider/person/10
// 進行解析,返回值爲10
longpersonid = ContentUris.parseId(uri);
String where ="_ID="+ personid;// 獲取指定id的記錄
where += !TextUtils.isEmpty(selection) ?" and ("+ selection +")":"";// 把其它條件附加上
count = db.update("teacher", values, where, selectionArgs);
break;
default:
thrownewIllegalArgumentException("Unknown URI "+ uri);
}
db.close();
returncount;
}
@Override
publicString getType(Uri uri) {
switch(uriMatcher.match(uri)) {
caseTEACHERS:
returnCONTENT_TYPE;
caseTEACHER:
returnCONTENT_TYPE_ITME;
default:
thrownewIllegalArgumentException("Unknown URI "+ uri);
}
}
@Override
publicCursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
switch(uriMatcher.match(uri)) {
caseTEACHERS:
returndb.query("teacher", projection, selection, selectionArgs,null,null, sortOrder);
caseTEACHER:
// 進行解析,返回值爲10
longpersonid = ContentUris.parseId(uri);
String where ="_ID="+ personid;// 獲取指定id的記錄
where += !TextUtils.isEmpty(selection) ?" and ("+ selection +")":"";// 把其它條件附加上
returndb.query("teacher", projection, where, selectionArgs,null,null, sortOrder);
default:
thrownewIllegalArgumentException("Unknown URI "+ uri);
}
}
}
|
一、這裏咱們在ArticlesProvider類的內部中定義了一個DBHelper類,它繼承於SQLiteOpenHelper類,它用是用輔助咱們操做數據庫的。使用這個DBHelper類來輔助操做數據庫的好處是隻有當咱們第一次對數據庫時行操做時,系統纔會執行打開數據庫文件的操做。拿咱們這個例子來講,只有第三方應用程序第一次調用query、insert、update或者delete函數來操做數據庫時,咱們纔會真正去打開相應的數據庫文件。這樣在onCreate函數裏,就不用執行打開數據庫的操做,由於這是一個耗時的操做,而在onCreate函數中,要避免執行這些耗時的操做。
二、咱們在實現本身的Content Provider時,必須繼承於ContentProvider類,而且實現如下六個函數:
-- onCreate(),用來執行一些初始化的工做。
-- query(Uri, String[], String, String[], String),用來返回數據給調用者。
-- insert(Uri, ContentValues),用來插入新的數據。
-- update(Uri, ContentValues, String, String[]),用來更新已有的數據。
-- delete(Uri, String, String[]),用來刪除數據。
-- getType(Uri),用來返回數據的MIME類型。
四、manifest
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<!--?xml version="1.0"encoding="utf-8"?-->
<manifest xmlns:android="
http://schemas.android.com/apk/res/android"package="hb.android.contentProvider"android:versioncode="1"android:versionname="1.0">
<uses-sdk android:minsdkversion="8">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER">
</category></action></intent-filter>
</activity>
<provider android:name=".TeacherContentProvider"android:authorities="hb.android.contentProvider"android:multiprocess="false">
</provider></application>
</uses-sdk></manifest>
|
在配置Content Provider的時候,最重要的就是要指定它的authorities屬性了,只有配置了這個屬性,第三方應用程序才能經過它來找到這個Content Provider。這要須要注意的,這裏配置的authorities屬性的值是和咱們前面在Articles.java文件中定義的AUTHORITY常量的值是一致的。另一個屬性multiprocess是一個布爾值,它表示這個Content Provider是否能夠在每一個客戶進程中建立一個實例,這樣作的目的是爲了減小進程間通訊的開銷。這裏咱們爲了減小沒必要要的內存開銷,把屬性multiprocess的值設置爲false,使得系統只能有一個Content Provider實例存在,它運行在本身的進程中。在這個配置文件裏面,咱們還能夠設置這個Content Provider的訪問權限,這裏咱們爲了簡單起見,就不設置權限了。
六、佈局文件
1
2
3
4
5
6
7
8
9
|
<!--?xml version="1.0"encoding="utf-8"?-->
<linearlayout xmlns:android="
http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">
<button android:id="@+id/insert"android:text="@string/insert"android:layout_width="fill_parent"android:layout_height="wrap_content">
</button><button android:id="@+id/query"android:text="@string/query"android:layout_width="fill_parent"android:layout_height="wrap_content">
</button><button android:id="@+id/querys"android:text="@string/querys"android:layout_width="fill_parent"android:layout_height="wrap_content">
</button><button android:id="@+id/update"android:text="@string/update"android:layout_width="fill_parent"android:layout_height="wrap_content">
</button><button android:id="@+id/delete"android:text="@string/delete"android:layout_width="fill_parent"android:layout_height="wrap_content">
</button></linearlayout>
|
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
|
packagehb.android.contentProvider;
importjava.util.Date;
importandroid.app.Activity;
importandroid.content.ContentResolver;
importandroid.content.ContentValues;
importandroid.database.Cursor;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
/**
* 這個類用來測試ContentProvider是否可用。經過 給定的uri訪問,數據庫;
*
* @author HB
*
*/
publicclassTeacherActivityextendsActivity {
Button insert;
Button query;
Button update;
Button delete;
Button querys;
Uri uri = Uri.parse("
content://hb.android.contentProvider/teacher");
/** Called when the activity is first created. */
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
insert = (Button) findViewById(R.id.insert);
query = (Button) findViewById(R.id.query);
update = (Button) findViewById(R.id.update);
delete = (Button) findViewById(R.id.delete);
querys = (Button) findViewById(R.id.querys);
// 綁定監聽器的兩種方法一;
insert.setOnClickListener(newInsertListener());
query.setOnClickListener(newQueryListener());
// 方法二
update.setOnClickListener(newOnClickListener() {
publicvoidonClick(View v) {
// TODO Auto-generated method stub
ContentResolver cr = getContentResolver();
ContentValues cv =newContentValues();
cv.put("name","huangbiao");
cv.put("date_added", (newDate()).toString());
inturi2 = cr.update(uri, cv,"_ID=?",newString[]{"3"});
System.out.println("updated"+":"+uri2);
}
});
delete.setOnClickListener(newOnClickListener() {
publicvoidonClick(View v) {
ContentResolver cr = getContentResolver();
cr.delete(uri,"_ID=?",newString[]{"2"});
}
});
querys.setOnClickListener(newOnClickListener() {
publicvoidonClick(View v) {
// TODO Auto-generated method stub
ContentResolver cr = getContentResolver();
// 查找id爲1的數據
Cursor c = cr.query(uri,null,null,null,null);
System.out.println(c.getCount());
c.close();
}
});
}
classInsertListenerimplementsOnClickListener {
publicvoidonClick(View v) {
// TODO Auto-generated method stub
ContentResolver cr = getContentResolver();
ContentValues cv =newContentValues();
cv.put("title","jiaoshou");
cv.put("name","jiaoshi");
cv.put("sex",true);
Uri uri2 = cr.insert(uri, cv);
System.out.println(uri2.toString());
}
}
classQueryListenerimplementsOnClickListener {
publicvoidonClick(View v) {
// TODO Auto-generated method stub
ContentResolver cr = getContentResolver();
// 查找id爲1的數據
Cursor c = cr.query(uri,null,"_ID=?",newString[] {"1"},null);
//這裏必需要調用 c.moveToFirst將遊標移動到第一條數據,否則會出現index -1 requested , with a size of 1錯誤;cr.query返回的是一個結果集。
if(c.moveToFirst() ==false) {
// 爲空的Cursor
return;
}
intname = c.getColumnIndex("name");
System.out.println(c.getString(name));
c.close();
}
}
}
|
組件Content Provider中的數據更新通知機制和Android系統中的廣播(Broadcast)通知機制的實現思路是類似的。
在Android的廣播機制中,首先是接收者對本身感興趣的廣播進行註冊,接着當發送者發出這些廣播時,接收者就會獲得通知了。更多關於Android系統的廣播機制的知識,能夠參考前面Android四大組件--Broadcast Receiver詳解這一文章。
然而,Content Provider中的數據監控機制與Android系統中的廣播機制又有三個主要的區別,
一是前者是經過URI來把通知的發送者和接收者關聯在一塊兒的,然後者是經過Intent來關聯的,
二是前者的通知註冊中心是由ContentService服務來扮演的,然後者是由ActivityManagerService服務來扮演的,
三是前者負責接收數據更新通知的類必需要繼承ContentObserver類,然後者要繼承BroadcastReceiver類。
之因此會有這些區別,是因爲Content Proivder組件的數據共享功能自己就是創建在URI的基礎之上的,所以專門針對URI來設計另一套通知機制會更實用和方便,而Android系統的廣播機制是一種更加通用的事件通知機制,它的適用範圍會更普遍一些。