android: 內容提供器簡介


我們學了 Android 數據持久化的技術,包括文件存儲、SharedPreferences 存 儲、以及數據庫存儲。不知道你有沒有發現,使用這些持久化技術所保存的數據都只能在當 前應用程序中訪問。雖然文件和 SharedPreferences 存儲中提供了 MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 這兩種操作模式,用於供給其他的應用程序訪問當前應用 的數據,但這兩種模式在 Android 4.2 版本中都已被廢棄了。為什么呢?因為 Android 官方已 經不再推薦使用這種方式來實現跨程序數據共享的功能,而是應該使用更加安全可靠的內容 提供器技術。

可能你會有些疑惑,為什么要將我們程序中的數據共享給其他程序呢?當然,這個要視 情況而定的,比如說賬號和密碼這樣的隱私數據顯然是不能共享給其他程序的,不過一些可 以讓其他程序進行二次開發的基礎性數據,我們還是可以選擇將其共享的。例如系統的電話 簿程序,它的數據庫中保存了很多的聯系人信息,如果這些數據都不允許第三方的程序進行 訪問的話,恐怕很多應用的功能都要大打折扣了。除了電話簿之外,還有短信、媒體庫等程 序都實現了跨程序數據共享的功能,而使用的技術當然就是內容提供器了,下面我們就來對 這一技術進行深入的探討。

內容提供器簡介

 內容提供器(Content Provider)主要用於在不同的應用程序之間實現數據共享的功能, 它提供了一套完整的機制,允許一個程序訪問另一個程序中的數據,同時還能保證被訪數據 的安全性。目前,使用內容提供器是 Android 實現跨程序共享數據的標准方式。

不同於文件存儲和 SharedPreferences 存儲中的兩種全局可讀寫操作模式,內容提供器可 以選擇只對哪一部分數據進行共享,從而保證我們程序中的隱私數據不會有泄漏的風險。

內容提供器的用法一般有兩種,一種是使用現有的內容提供器來讀取和操作相應程序中 的數據,另一種是創建自己的內容提供器給我們程序的數據提供外部訪問接口。那么接下來 我們就一個一個開始學習吧,首先從使用現有的內容提供器開始。

 

7.2    訪問其他程序中的數據

 

當一個應用程序通過內容提供器對其數據提供了外部訪問接口,任何其他的應用程序就 都可以對這部分數據進行訪問。Android 系統中自帶的電話簿、短信、媒體庫等程序都提供 了類似的訪問接口,這就使得第三方應用程序可以充分地利用這部分數據來實現更好的功 能。下面我們就來看一看,內容提供器到底是如何使用的。

 

7.2.1    ContentResolver 的基本用法

 

對於每一個應用程序來說,如果想要訪問內容提供器中共享的數據,就一定要借助 ContentResolve 類,可以通過 Context 中的 getContentResolver() 方法獲取到該類的實例。 ContentResolver 中提供了一系列的方法用於對數據進行 CRUD 操作,其中 insert()方法用於 添加數據,update()方法用於更新數據,delete()方法用於刪除數據,query()方法用於查詢數 據。有沒有似曾相識的感覺?沒錯,SQLiteDatabase 中也是使用的這幾個方法來進行 CRUD 操作的,只不過它們在方法參數上稍微有一些區別。

不同於 SQLiteDatabase,ContentResolver 中的增刪改查方法都是不接收表名參數的,而 是使用一個 Uri 參數代替,這個參數被稱為內容 URI。內容 URI 給內容提供器中的數據建立 了唯一標識符,它主要由兩部分組成,權限(authority)和路徑(path)。權限是用於對不同 的應用程序做區分的,一般為了避免沖突,都會采用程序包名的方式來進行命名。比如某個 程序的包名是 com.example.app ,那么該程序對應的權限就可以命名為 com.example.app. provider。路徑則是用於對同一應用程序中不同的表做區分的,通常都會添加到權限的后面。 比如某個程序的數據庫里存在兩張表,table1 和 table2,這時就可以將路徑分別命名為/table1 和/table2,然后把權限和路徑進行組合,內容 URI 就變成了 com.example.app.provider/table1 和 com.example.app.provider/table2。不過,目前還很難辨認出這兩個字符串就是兩個內容 URI,我們還需要在字符串的頭部加上協議聲明。因此,內容 URI 最標准的格式寫法如下:

 

content://com.example.app.provider/table1 content://com.example.app.provider/table2

有沒有發現,內容 URI 可以非常清楚地表達出我們想要訪問哪個程序中哪張表里的數 據。也正是因此,ContentResolver 中的增刪改查方法才都接收 Uri 對象作為參數,因為使用 表名的話系統將無法得知我們期望訪問的是哪個應用程序里的表。

在得到了內容 URI 字符串之后,我們還需要將它解析成 Uri 對象才可以作為參數傳入。 解析的方法也相當簡單,代碼如下所示:

 

Uri uri = Uri.parse("content://com.example.app.provider/table1")

只需要調用 Uri.parse()方法,就可以將內容 URI 字符串解析成 Uri 對象了。

 

現在我們就可以使用這個 Uri 對象來查詢 table1 表中的數據了,代碼如下所示:

 

Cursor cursor = getContentResolver().query(

uri,

projection, selection, selectionArgs, sortOrder);

這些參數和 SQLiteDatabase 中 query()方法里的參數很像,但總體來說要簡單一些,畢 竟這是在訪問其他程序中的數據,沒必要構建過於復雜的查詢語句。下表對使用到的這部分 參數進行了詳細的解釋。

 

query()方法參數

對應 SQL 部分

描述

uri

from table_name

指定查詢某個應用程序下的某一張表

projection

select column1, column2

指定查詢的列名

selection

where column = value

指定 where 的約束條件

selectionArgs

-

為 where 中的占位符提供具體的值

orderBy

order by column1, column2

指定查詢結果的排序方式

 

 

查詢完成后返回的仍然是一個 Cursor 對象,這時我們就可以將數據從 Cursor 對象中逐

個讀取出來了。讀取的思路仍然是通過移動游標的位置來遍歷 Cursor 的所有行,然后再取出 每一行中相應列的數據,代碼如下所示:

 

if (cursor != null) {

while (cursor.moveToNext()) {

String column1 = cursor.getString(cursor.getColumnIndex("column1"));

int column2 = cursor.getInt(cursor.getColumnIndex("column2"));

}

cursor.close();

}

掌握了最難的查詢操作,剩下的增加、修改、刪除操作就更不在話下了。我們先來看看 如何向 table1 表中添加一條數據,代碼如下所示:

 

ContentValues values = new ContentValues(); values.put("column1", "text"); values.put("column2", 1); getContentResolver().insert(uri, values);

可以看到,仍然是將待添加的數據組裝到 ContentValues 中,然后調用 ContentResolver的 insert()方法,將 Uri 和 ContentValues 作為參數傳入即可。

現 在 如 果 我 們 想 要 更 新 這 條 新 添 加 的 數 據 , 把 column1 的 值 清 空 , 可 以 借 助

ContentResolver 的 update()方法實現,代碼如下所示:

 

ContentValues values = new ContentValues();

values.put("column1", "");

getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new

String[] {"text", "1"});

注意上述代碼使用了 selection 和 selectionArgs 參數來對想要更新的數據進行約束,以防 止所有的行都會受影響。

最后,可以調用 ContentResolver 的 delete()方法將這條數據刪除掉,代碼如下所示:

 

getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

到這里為止,我們就把 ContentResolver 中的增刪改查方法全部學完了。是不是感覺非常 簡單?因為這些知識早在上一章中學習 SQLiteDatabase 的時候你就已經掌握了,所需特別注 意的就只有 uri 這個參數而已。


免責聲明!

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



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