學習筆記——ContentProvider

ContentProvider內部如何保存數據由其設計者決定。但是所有的ContentProvider都實現一組通用的方法,用來提供數據的增刪改查功能。

客戶端通常不會直接使用這些方法,大多數是通過ContentResolver對象實現對ContentProvider的操作,開發人員可以通過調用Activity或者其他應用程序組建的實現類中的getContentResolver()方法來獲得ContentProvider對象。

使用ContentResolver提供的方法可以獲得ContentProvider中任何感興趣的數據。

當開始查詢時,Android系統確認查詢的目標ContentProvider並確保它正在運行。系統會初始化所有的ContentProvider類的對象,開發人員不必完成此類操作。實際上,開發人員根本不會直接使ContentProvider類的對象。通常,每個類型的ContentProvider僅有一個單獨的實例。但是該實例能與位於不同應用程序和進程的多個ContentProvider類對象通信。不同進程之間的通信由ContentProvider類和ContentResolver類處理

1.1數據模型

ContentResolver使用基於數據庫模型的簡單表格來提供其中的 數據,這裏每行代表一條記錄,每列代表特定類型和含義的數據。例如,聯繫人的信息可能以表所示的方式提供。

——ID NAME NUMBER EMAIL
001 王xx 123****** 123**@163.com
002 張xx 333****** 333******@163.com
每條記錄包含一個數值型的_ID字段,它用於表格中唯一標識改記錄。ID能用於匹配相關表格中的記錄,例如在一個表格中查詢聯繫人電話,在另一表格中查詢其照片。

查詢返回一個Cursor對象,它能遍歷各行各列來讀取各個字段的值,對於各個類型的數據,它都提供了專用的方法。因此,爲了讀取字段的數據,開發人員必須知道當前字段包含的數據類型。

1.2URI的用法

每個ContentProvider提供公共的URI(使用Uri類包裝)來唯一標識其數據集。管理多個數據集(多個表格)的ContentProvider爲每個數據集提供了單獨的URI。所有爲provider提供的URI都以“content://"作爲前綴,”content://“模式表示數據由ContentProvider來管理。

如果自定義ContentProvider,則應該爲其URI也定義一個常量,來簡化客戶端代碼並讓日後更新更加簡潔。Android爲當前平臺提供的ContentProvider定義了CONTENT_URI常量。匹配電話號碼到聯繫人表格的URI和匹配保存聯繫人照片表格的URI分別如下:

android.provider.Contacts.Phones.CONTENT_URI;

android.provider.Contacts.Photos.CONTETN_URI;

URI常量用於所有與ContentProvider的交互中。每個ContentProvider位方法使用URI作爲其第一個參數,它標識ContentProvider應該使用哪個provider及其中的哪個表格。

下面是ContentUri重要部分的總結:

content://com.example.tofun/dba/001

1.紅色(content://):標準的前綴,用於標識改數據由ContentProvider管理。它永遠不用修改。

2.藍色(com.example.tofun):URI的authority部分,它標識ContentProvider。對於第三方應用,該部分應該是完整的類名(使用小寫形式)來保證唯一性。在<provider>元素的authorities屬性中聲明authorty。

3.綠色(/dba):ContentProvider的路徑部分,用於決定哪類數據被請求。如果ContentProvider僅提供一種數據類型,這部分可以省略。如果provider提供幾種數據類型,包括子類型,這部分可以由幾部分組成。

4.黃色(/001):被請求的特定記錄的ID值。這是被請求記錄的ID值。如果請求不僅限於單條記錄,則該部分應該刪除。

2.預定義ContentProvider

Android系統爲常用數據類型提供了很多預定義的ContentProvider(聲音,視頻,圖片,聯繫人等),它們大都位於android.provider包中。開發人員可以查詢這些provider以獲得其中包含的信息(儘管有些需要適當的權限來讀取數據)。Android系統提供的常見ContentProvider說明如下:

1.Browser:讀取或修改書籤,瀏覽歷史或網絡搜索。

2.CallLog:查看或更新通話歷史。

3.Contacts:獲取,修改或保存聯繫人信息。

4.LiveFolders:由ContentProvider提供內容的特定文件夾。

5.MediaStore:訪問聲音,視頻和圖片。

6.Setting:查看和獲取藍牙設置,鈴聲和其他設備偏好。

7.SearchRecentSuggestions:能被配置以使用查找意見provider操作。

8.SyncStateContact:用於使用數據數組賬號關聯數據的ContentProvider約束。希望使用標準方式保存數據的provider可以使用它。

9.UserDictionary:在可預測文本輸入誰,提供用戶定義單詞給輸入法使用。應用程序和輸入法能增加數據到該字典。單詞能關聯頻率信息和本地化信息。

2.1查詢數據

開發人員需要下面3條信息才能查詢Contentprovider中的數據:

1.標識改ContentProvider的URI。

2.需要查詢的數據字段名稱。

3.字段中數據的類型。

如果查詢特定的記錄,則還需要提供該記錄的ID值。

爲了查詢ContentProvider中do數據,開發人員需要使用ContentResolver.query()或Activity.ManagedQuery()方法。這兩個方法使用相同的參數,並且都返回Cursor對象。然而,managedQuery()方法導致Activity管理Cursor的聲明週期。託管的Cursor處理所有細節,例如當Activity暫停時卸載自身,當Activity重啓時加載自身。調用Activity.startManagingCursor()方法可以讓Activity管理未託管的Cursor對象。

query()和managedQuery()方法的第一個參數是provider的URI,級標識特定ContentProvider和數據集的CONTENT_URI常量。

爲了限制返回一條記錄,可以再URI結尾增加改記錄的_ID值,即將匹配ID值的字符串作爲URI路徑部分的結尾片段。例如,ID值是10,URI將是:

content://..../10

有些輔助方法,特別是ContentUris.withAppednedId()和Uri.withAppednedPath(),能輕鬆將ID增加到URI。這兩個方法都是靜態方法並返回一個增加了ID的URI對象。

query和managedQuery()方法的其他參數用來更加細緻地限制查詢結果,它們是:

1.應該返回的數據列名稱。null值表示返回全部列:否則,僅返回列出的列。全部預定義ContentProvider都爲其列定義了常量。例如,android.provider.Contacts.Phones類定義了_ID,NUMBER,NUMBER_KEY,NAME等常量

2.決定哪些行被返回的過濾器,格式類似SQL的WHERE語句(但是不包含WHERE自身)。null表示返回全部行(除非URI限制查詢結果爲單行記錄)。

3.選擇參數。

4.返回記錄的排序器,格式類似SQL的ORDER BY語句(但是不包含ORDER BY自身)。null表示以默認順序返回,可能是無序的。

查詢返回一組零條或多條數據庫記錄。列明,默認順序和數據類型對每個ContentProvider都是特別的。但是每個provider都有一個_ID列,它爲每條記錄保存唯一的數組ID。每個provider也能使用_COUNT報告返回結果中記錄的行數,改制在各行都是相同的。

獲得數據使用Cursor對象處理,它能向前或者向後遍歷整個結果集。

2.2增加記錄

爲了向ContentProvider中增加新數據,首先需要在ContentValues對象中建立鍵值對映射,這裏每個鍵匹配ContentProvider中的列名,每個值是該列中希望增加的值。然後調用ContentResolver.insert()方法並傳遞給它provider的URI參數和ContentValues的映射。該方法返回新紀錄的完整URI,既增加了新紀錄的ID的URI。

2.3增加新值

一旦記錄存在,開發人員可以向其增加新信息或者修改已經存在的信息。增加記錄到Contacts數據庫的最佳方式是增加保存新數據的表名到代表記錄的URI,然後使用組裝好的URI來增加新數據。每個Contacts表格以CONTENT_DIRECTORY常量的方式提供名稱作爲該用途。

3.自定義ContentProvider

如果開發人員希望共享自己的數據,則有兩個選擇:

1.創建自定義的ContentProvider(一個ContentProvider的子類)

2.如果有預定義的ContentProvider,管理相同的數據類型並且有寫入權限,則可以向其中增加數據。

如果自定義Contentprovider,則需要完成以下操作:

1.建立數據存儲系統。大多數ContentProvider使用Android文件存儲方法或者SQLite數據庫保存數據,但是開發人員可以使用任何方式存儲。Android提供了SQLiteOpenHelper類幫助創建數據庫,SQLiteDatabase類管理數據庫。

2.繼承ContentProvider類來提供數據訪問方式。

3.在應用程序清單文件中聲明ContentProvider

下面介紹後兩個任務。

3.1繼承ContentProvider類

定義ContentProvider類的子類,以便使用ContentResolver和Cursor類帶來的便捷來共享數據。原則上,這意味着需要實現ContentProvider類定義的6個方法。

1.public boolean onCreate():用於初始化provider

2.public Cursor query(Uri uri,String[] projection,String,selection,String[] selectionArgs,String sortOrder):返回數據給調用者

3.public Uri insert(Uri uri,ContentValues values):插入

4.public int update(Uri uri,ContentValues values,String selection,String [] selectionArgs):更新

5.public int delete(Uri uri,String selection,String[] selectionArgs):刪除

6.public String getType(Uri uri):返回ContentProvider數據的MIME類型。

3.2聲明ContentProvider

在AndroidManifest.xml文件中定義<provider>標籤。沒有在清單文件中聲明,自定義的ContentProvider對於Android系統不可見。

name屬性的值是ContentProvider類的子類的完整名稱;authorities屬性是provider定義的content:URI中authority部分,例如

<provider android:name="com.example.EmployeeProvider" android:authorities="com.exmaple.employeeprovider"/>
其他<provider>屬性能設置讀寫數據的權限,提供顯示給用戶的圖標或文本,棄用或禁用provider等。如果數據不需要在多個運行着的ContentProvider間同步,則設置multiprocess爲true。這允許在各個客戶端進程之間創建一個provider實例,從而避免執行IPC。

下面一個讀取聯繫人ID和姓名的例子

public class MainActivity extends Activity {
	private TextView tv;
	String[] columns = {Contacts._ID,Contacts.DISPLAY_NAME};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView)findViewById(R.id.tv);
        tv.setText(getQueryData());
    }

	private String getQueryData() {
		StringBuffer sb = new StringBuffer();
		ContentResolver resolver = this.getContentResolver();
		Cursor cursor = resolver.query(Contacts.CONTENT_URI, columns, null, null, null);
		int idIndex = cursor.getColumnIndex(columns[0]);
		int nameIndex = cursor.getColumnIndex(columns[1]);
		for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
			int id = cursor.getInt(idIndex);
			String name = cursor.getString(nameIndex);
			sb.append(id+":"+name+"\n");
		}
		return sb.toString();
	}
}
需要聲明讀取聯繫人的權限

<uses-permission android:name="android.permission.READ_CONTACTS"/>


發佈了9 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章