Android編程之創(chuàng)建自己的內(nèi)容提供器實(shí)現(xiàn)方法
本文實(shí)例講述了Android編程之創(chuàng)建自己的內(nèi)容提供器實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
我們學(xué)習(xí)了如何在自己的程序中訪問(wèn)其他應(yīng)用程序的數(shù)據(jù)??傮w來(lái)說(shuō)思 路還是非常簡(jiǎn)單的,只需要獲取到該應(yīng)用程序的內(nèi)容 URI,然后借助 ContentResolver 進(jìn)行CRUD 操作就可以了。可是你有沒(méi)有想過(guò),那些提供外部訪問(wèn)接口的應(yīng)用程序都是如何實(shí)現(xiàn)這種功能的呢?它們又是怎樣保證數(shù)據(jù)的安全性,使得隱私數(shù)據(jù)不會(huì)泄漏出去?
創(chuàng)建內(nèi)容提供器的步驟
前面已經(jīng)提到過(guò),如果想要實(shí)現(xiàn)跨程序共享數(shù)據(jù)的功能,官方推薦的方式就是使用內(nèi)容提供器,可以通過(guò)新建一個(gè)類去繼承 ContentProvider 的方式來(lái)創(chuàng)建一個(gè)自己的內(nèi)容提供器。 ContentProvider 類中有六個(gè)抽象方法,我們?cè)谑褂米宇惱^承它的時(shí)候,需要將這六個(gè)方法全 部重寫(xiě)。新建 MyProvider 繼承自 ContentProvider,代碼如下所示:
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
}
在這六個(gè)方法中,相信大多數(shù)你都已經(jīng)非常熟悉了,我再來(lái)簡(jiǎn)單介紹一下吧。
1. onCreate()
初始化內(nèi)容提供器的時(shí)候調(diào)用。通常會(huì)在這里完成對(duì)數(shù)據(jù)庫(kù)的創(chuàng)建和升級(jí)等操作, 返回 true 表示內(nèi)容提供器初始化成功,返回 false 則表示失敗。注意,只有當(dāng)存在 ContentResolver 嘗試訪問(wèn)我們程序中的數(shù)據(jù)時(shí),內(nèi)容提供器才會(huì)被初始化。
2. query()
從內(nèi)容提供器中查詢數(shù)據(jù)。使用 uri 參數(shù)來(lái)確定查詢哪張表,projection 參數(shù)用于確 定查詢哪些列,selection 和 selectionArgs 參數(shù)用于約束查詢哪些行,sortOrder 參數(shù)用于 對(duì)結(jié)果進(jìn)行排序,查詢的結(jié)果存放在 Cursor 對(duì)象中返回。
3. insert()
向內(nèi)容提供器中添加一條數(shù)據(jù)。使用 uri 參數(shù)來(lái)確定要添加到的表,待添加的數(shù)據(jù) 保存在 values 參數(shù)中。添加完成后,返回一個(gè)用于表示這條新記錄的 URI。
4. update()
更新內(nèi)容提供器中已有的數(shù)據(jù)。使用 uri 參數(shù)來(lái)確定更新哪一張表中的數(shù)據(jù),新數(shù) 據(jù)保存在 values 參數(shù)中,selection 和 selectionArgs 參數(shù)用于約束更新哪些行,受影響的 行數(shù)將作為返回值返回。
5. delete()
從內(nèi)容提供器中刪除數(shù)據(jù)。使用 uri 參數(shù)來(lái)確定刪除哪一張表中的數(shù)據(jù),selection和 selectionArgs 參數(shù)用于約束刪除哪些行,被刪除的行數(shù)將作為返回值返回。
6. getType()
根據(jù)傳入的內(nèi)容 URI 來(lái)返回相應(yīng)的 MIME 類型。 可以看到,幾乎每一個(gè)方法都會(huì)帶有 Uri 這個(gè)參數(shù),這個(gè)參數(shù)也正是調(diào)用 ContentResolver的增刪改查方法時(shí)傳遞過(guò)來(lái)的。而現(xiàn)在,我們需要對(duì)傳入的 Uri 參數(shù)進(jìn)行解析,從中分析出 調(diào)用方期望訪問(wèn)的表和數(shù)據(jù)。
回顧一下,一個(gè)標(biāo)準(zhǔn)的內(nèi)容 URI 寫(xiě)法是這樣的:
content://com.example.app.provider/table1
這就表示調(diào)用方期望訪問(wèn)的是 com.example.app 這個(gè)應(yīng)用的 table1 表中的數(shù)據(jù)。除此之 外,我們還可以在這個(gè)內(nèi)容 URI 的后面加上一個(gè) id,如下所示:
content://com.example.app.provider/table1/1
這就表示調(diào)用方期望訪問(wèn)的是 com.example.app 這個(gè)應(yīng)用的 table1 表中 id 為 1 的數(shù)據(jù)。 內(nèi)容 URI 的格式主要就只有以上兩種,以路徑結(jié)尾就表示期望訪問(wèn)該表中所有的數(shù)據(jù),以 id 結(jié)尾就表示期望訪問(wèn)該表中擁有相應(yīng) id 的數(shù)據(jù)。我們可以使用通配符的方式來(lái)分別匹 配這兩種格式的內(nèi)容 URI,規(guī)則如下。
1. *:表示匹配任意長(zhǎng)度的任意字符
2. #:表示匹配任意長(zhǎng)度的數(shù)字 所以,一個(gè)能夠匹配任意表的內(nèi)容 URI 格式就可以寫(xiě)成:
content://com.example.app.provider/*
而一個(gè)能夠匹配 table1 表中任意一行數(shù)據(jù)的內(nèi)容 URI 格式就可以寫(xiě)成:
content://com.example.app.provider/table1/#
接著,我們?cè)俳柚?UriMatcher 這個(gè)類就可以輕松地實(shí)現(xiàn)匹配內(nèi)容 URI 的功能。UriMatcher 中提供了一個(gè) addURI()方法,這個(gè)方法接收三個(gè)參數(shù),可以分別把權(quán)限、路徑和一個(gè)自定義 代碼傳進(jìn)去。這樣,當(dāng)調(diào)用 UriMatcher 的 match()方法時(shí),就可以將一個(gè) Uri 對(duì)象傳入,返 回值是某個(gè)能夠匹配這個(gè) Uri 對(duì)象所對(duì)應(yīng)的自定義代碼,利用這個(gè)代碼,我們就可以判斷出 調(diào)用方期望訪問(wèn)的是哪張表中的數(shù)據(jù)了。修改 MyProvider 中的代碼,如下所示:
public class MyProvider extends ContentProvider {
public static final int TABLE1_DIR = 0;
public static final int TABLE1_ITEM = 1;
public static final int TABLE2_DIR = 2;
public static final int TABLE2_ITEM = 3;
private static UriMatcher uriMatcher; static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider ", "table1/#", TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider ", "table2", TABLE2_ITEM);
uriMatcher.addURI("com.example.app.provider ", "table2/#", TABLE2_ITEM);
}
……
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
// 查詢table1表中的所有數(shù)據(jù)
break;
case TABLE1_ITEM:
// 查詢table1表中的單條數(shù)據(jù)
break;
case TABLE2_DIR:
// 查詢table2表中的所有數(shù)據(jù)
break;
case TABLE2_ITEM:
// 查詢table2表中的單條數(shù)據(jù)
break;
default:
break;
}
……
}
……
}
可以看到,MyProvider 中新增了四個(gè)整型常量,其中 TABLE1_DIR 表示訪問(wèn) table1 表 中的所有數(shù)據(jù),TABLE1_ITEM 表示訪問(wèn) table1 表中的單條數(shù)據(jù),TABLE2_DIR 表示訪問(wèn) table2 表中的所有數(shù)據(jù),TABLE2_ITEM 表示訪問(wèn) table2 表中的單條數(shù)據(jù)。接著在靜態(tài)代碼 塊里我們創(chuàng)建了 UriMatcher 的實(shí)例,并調(diào)用 addURI()方法,將期望匹配的內(nèi)容 URI 格式傳 遞進(jìn)去,注意這里傳入的路徑參數(shù)是可以使用通配符的。然后當(dāng) query()方法被調(diào)用的時(shí)候, 就會(huì)通過(guò) UriMatcher 的 match()方法對(duì)傳入的 Uri 對(duì)象進(jìn)行匹配,如果發(fā)現(xiàn) UriMatcher 中某 個(gè)內(nèi)容 URI 格式成功匹配了該 Uri 對(duì)象,則會(huì)返回相應(yīng)的自定義代碼,然后我們就可以判斷 出調(diào)用方期望訪問(wèn)的到底是什么數(shù)據(jù)了。
上述代碼只是以 query()方法為例做了個(gè)示范,其實(shí) insert()、update()、delete()這幾個(gè)方 法的實(shí)現(xiàn)也是差不多的,它們都會(huì)攜帶 Uri 這個(gè)參數(shù),然后同樣利用 UriMatcher 的 match() 方法判斷出調(diào)用方期望訪問(wèn)的是哪張表,再對(duì)該表中的數(shù)據(jù)進(jìn)行相應(yīng)的操作就可以了。
除此之外,還有一個(gè)方法你會(huì)比較陌生,即 getType()方法。它是所有的內(nèi)容提供器都必 須提供的一個(gè)方法,用于獲取 Uri 對(duì)象所對(duì)應(yīng)的 MIME 類型。一個(gè)內(nèi)容 URI 所對(duì)應(yīng)的 MIME 字符串主要由三部分組分,Android 對(duì)這三個(gè)部分做了如下格式規(guī)定。
1. 必須以 vnd 開(kāi)頭。
2. 如果內(nèi)容 URI 以路徑結(jié)尾,則后接 android.cursor.dir/,如果內(nèi)容 URI 以 id 結(jié)尾, 則后接 android.cursor.item/。
3. 最后接上 vnd.<authority>.<path>。
所以,對(duì)于 content://com.example.app.provider/table1 這個(gè)內(nèi)容 URI,它所對(duì)應(yīng)的 MIME
類型就可以寫(xiě)成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
對(duì)于 content://com.example.app.provider/table1/1 這個(gè)內(nèi)容 URI,它所對(duì)應(yīng)的 MIME 類型 就可以寫(xiě)成:
vnd.android.cursor.item/vnd. com.example.app.provider.table1
現(xiàn)在我們可以繼續(xù)完善 MyProvider 中的內(nèi)容了,這次來(lái)實(shí)現(xiàn) getType()方法中的邏輯, 代碼如下所示:
public class MyProvider extends ContentProvider {
……
@Override
public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.
table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.
table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.
table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.
table2";
default:
break;
}
return null;
}
}
到這里,一個(gè)完整的內(nèi)容提供器就創(chuàng)建完成了,現(xiàn)在任何一個(gè)應(yīng)用程序都可以使用ContentResolver 來(lái)訪問(wèn)我們程序中的數(shù)據(jù)。那么前面所提到的,如何才能保證隱私數(shù)據(jù)不會(huì) 泄漏出去呢?其實(shí)多虧了內(nèi)容提供器的良好機(jī)制,這個(gè)問(wèn)題在不知不覺(jué)中已經(jīng)被解決了。因 為所有的 CRUD 操作都一定要匹配到相應(yīng)的內(nèi)容 URI 格式才能進(jìn)行的,而我們當(dāng)然不可能 向 UriMatcher 中添加隱私數(shù)據(jù)的 URI,所以這部分?jǐn)?shù)據(jù)根本無(wú)法被外部程序訪問(wèn)到,安全問(wèn)題也就不存在了。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android資源操作技巧匯總》、《Android編程開(kāi)發(fā)之SD卡操作方法匯總》、《Android文件操作技巧匯總》、《Android數(shù)據(jù)庫(kù)操作技巧總結(jié)》、《Android編程之a(chǎn)ctivity操作技巧總結(jié)》、《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》、《Android視圖View技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android開(kāi)發(fā)之ContentProvider的使用詳解
- Android中自定義ContentProvider實(shí)例
- 實(shí)例講解Android中ContentProvider組件的使用方法
- 基于Android ContentProvider的總結(jié)詳解
- Android中自定義ContentProvider實(shí)例
- 深入U(xiǎn)nderstanding Android ContentProvider詳解
- Android編程使用內(nèi)容提供者方式(ContentProvider)進(jìn)行存儲(chǔ)的方法
- Android內(nèi)容提供者ContentProvider用法實(shí)例分析
相關(guān)文章
Android自定義ScrollView實(shí)現(xiàn)放大回彈效果實(shí)例代碼
本篇文章主要介紹了Android自定義ScrollView實(shí)現(xiàn)放大回彈效果實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
flutter 怎么實(shí)現(xiàn)app整體灰色效果
Flutter 是 Google 開(kāi)源的 UI 工具包,幫助開(kāi)發(fā)者通過(guò)一套代碼庫(kù)高效構(gòu)建多平臺(tái)精美應(yīng)用,支持移動(dòng)、Web、桌面和嵌入式平臺(tái)。這篇文章給大家介紹flutter 怎么實(shí)現(xiàn)app整體灰色效果,感興趣的朋友一起看看吧2020-04-04
flutter 實(shí)現(xiàn)點(diǎn)擊下拉欄微信右上角彈出窗功能
這篇文章主要介紹了flutter 實(shí)現(xiàn)彈出窗點(diǎn)擊下拉欄微信右上角彈出窗功能,這段代碼使用的是PopupRoute這個(gè)路由類進(jìn)行實(shí)現(xiàn) 的,分步驟通過(guò)實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下2021-05-05
android實(shí)現(xiàn)簡(jiǎn)單儀表盤(pán)效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)單儀表盤(pán)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法
這篇文章主要介紹了Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
Android自定義SwipeRefreshLayout高仿微信朋友圈下拉刷新
這篇文章主要以社交APP的BOSS微信為例,介紹了Android自定義SwipeRefreshLayout高仿微信朋友圈下拉刷新,感興趣的小伙伴們可以參考一下2016-07-07
Android 自定義View手寫(xiě)簽名并保存圖片功能
這篇文章主要介紹了Android 自定義View手寫(xiě)簽名并保存圖片功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2020-03-03
MVVMLight項(xiàng)目Model?View結(jié)構(gòu)及全局視圖模型注入器
這篇文章主要為大家介紹了MVVMLight項(xiàng)目中Model及View的結(jié)構(gòu)及全局視圖模型注入器的使用說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-01-01
Android從0到完整項(xiàng)目(1)使用Android studio 創(chuàng)建項(xiàng)目詳解
本篇文章主要介紹了Android從0到完整項(xiàng)目(1)使用Android studio 創(chuàng)建項(xiàng)目詳解,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07

