前言
Content Provider——Android四大元件之一。
本文要點
1.Content Provider簡介
2.URI簡介
3.如何訪問Content Provider中資料
一、Content Provider簡介
Content Provider,Android四大元件之一。它是Android系統提供的在多個應用之間共享資料的一種機制。一個Content Provider類實現了一組標準的方法介面,從而能夠讓其他的應用儲存或讀取此Content Provider的各種資料型別。有幾點說明:
(1)每個ContentProvider都會對外提供一個公共的URI(包裝成Uri物件),如果應用程式有資料需要共享,就需要使用ContentProvider為這些資料定義一個URI,然後其他應用程式就可以通過ContentProvider傳入這個URI來對資料進行操作。
(2)我們的APP可以通過實現一個Content Provider的抽象介面將自己的資料暴露出去,也可以通過ContentResolver介面訪問Content Provider提供的資料;
(3)ContentResolver支援CRUD(create, retrieve, update, and delete)操作;
(4)Android系統提供了諸如:音訊、視訊、圖片、通訊錄等主要資料型別的Content Provider。我們也可以建立自己的Content Provider。
首先,Android是一個很重視安全性的系統(貌似Android系統的漏洞最多~~~),一個應用的資料對於其他應用來說私有的,除非你把資料儲存在SD卡上。但很多時候我們需要在程式之間共享資料,比如我們想獲取聯絡人的資訊之類的。這時Content Provider就提供了一個很好的解決方案,將資料的儲存、讀取細節隱藏,提供一個統一的介面供其它應用訪問,並且還可以做到許可權控制,在一定程度上保證資料的安全性。
其次就是程式間通訊(inter-process communication IPC)的問題,如果讓開發者自己來處理這些細節無疑會加大開發的難度。而Content Provider提供了類似於b/s結構的模式,b與c之間是以一種什麼方式去實現我們並不關心,就像我們大部分時候不用去關心網路到底是怎麼連線的。開發者應該關心的是怎麼去實現一個Content Provider或去呼叫一個Content Provider。
二、URI簡介
URI唯一標識了Provider中的資料,當應用程式訪問Content Provider中的資料時,URI將會是其中一個重要引數。URI包含了兩部分內容:(1)要操作的Content Provider物件(2)要操作的Content Provider中資料的型別。
URI由以下幾個部分組成:
(1)Scheme:在Android中URI的Scheme是不變的,即:Content://
(2)Authority:用於標識ContentProvider(API原文:A string that identifies the entire content provider.);
(3)Path:用來標識我們要操作的資料。零個或多個段,用正斜槓(/
)分割;
(4)ID:指定ID後,將操作指定ID的資料(ID也可以看成是path的一部分),ID在URI中是可選的(API原文:A unique numeric identifier for a single row in the subset of data identified by the preceding path part.)。
URI示例:
(1)content://media/internal/images 返回裝置上儲存的所有圖片;
(2)content://media/internal/images /10 返回裝置上儲存的ID為10的圖片
操作URI經常會使用到UriMatcher和ContentUris兩個類。
UriMatcher:用於匹配Uri;
ContentUris:用於操作Uri路徑後面的ID部分,如提供了方法withAppendedId()向URI中追加ID。
三、訪問Content Provider中資料
應用程式訪問Content Provider的內容需要用到ContentResolver物件,這裡以操作Android通訊錄提供的Content Provider為例來說明如何訪問Content Provider中的資料。
1.建立一個project:HelloContentProvider,MainActivity的Layout檔案命名為main.xml;
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloandroid" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:label="@string/title_activity_second" > </activity> <activity android:name=".ServiceActivity" android:label="@string/title_activity_service" > </activity> <service android:name=".MyService" > <intent-filter> <action android:name="android.guo.service.playmusic.MyService" /> </intent-filter> </service> <activity android:name=".ContentProviderActivity" android:label="@string/title_activity_content_provider" > </activity> </application> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> </manifest>
2.在檔案:AndroidManifest.xml中新增Contact的讀寫許可權;
3.在main.xml中新增幾個button:Insert,Query,Update,Delete,並繫結onClick事件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello Content Provider" /> <Button android:id="@+id/btnInsert" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="100dp" android:text="Insert" android:onClick="insertContact"/> <Button android:id="@+id/btnQuery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="100dp" android:text="Query" android:onClick="queryContacts"/> <Button android:id="@+id/btnUpdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="100dp" android:text="Update" android:onClick="updateContact"/> <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="100dp" android:text="Delete" android:onClick="deleteContact"/> </LinearLayout>
新增記錄:
要增加記錄,我們可以呼叫ContentResolver.insert()方法,該方法接受一個要增加的記錄的目標URI,以及一個包含了新記錄值的Map物件,呼叫後的返回值是新記錄的URI,包含記錄號。
上面的例子中我們都是基於聯絡人資訊簿這個標準的Content Provider,現在我們繼續來建立一個insertRecord() 方法以對聯絡人資訊簿中進行資料的新增:
private void insertRecords(String name, String phoneNo) { ContentValues values = new ContentValues(); values.put(People.NAME, name); Uri uri = getContentResolver().insert(People.CONTENT_URI, values); Log.d(”ANDROID”, uri.toString()); Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); values.clear(); values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE); values.put(People.NUMBER, phoneNo); getContentResolver().insert(numberUri, values); }
刪除記錄:
Content Provider中的getContextResolver.delete()方法可以用來刪除記錄,下面的記錄用來刪除裝置上所有的聯絡人資訊:
private void deleteRecords() { Uri uri = People.CONTENT_URI; getContentResolver().delete(uri, null, null); }
修改記錄:
我們可以使用ContentResolver.update()方法來修改資料,我們來寫一個修改資料的方法:
private void updateRecord(int recNo, String name) { Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo); ContentValues values = new ContentValues(); values.put(People.NAME, name); getContentResolver().update(uri, values, null, null); }
查詢記錄:
Cursor cur = managedQuery(person, null, null, null);
這個查詢返回一個包含所有資料欄位的遊標,我們可以通過迭代這個遊標來獲取所有的資料:
package com.wissen.testApp; public class ContentProviderDemo extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); displayRecords(); } private void displayRecords() { //該陣列中包含了所有要返回的欄位 String columns[] = new String[] { People.NAME, People.NUMBER }; Uri mContacts = People.CONTENT_URI; Cursor cur = managedQuery( mContacts, columns, // 要返回的資料欄位 null, // WHERE子句 null, // WHERE 子句的引數 null // Order-by子句 ); if (cur.moveToFirst()) { String name = null; String phoneNo = null; do { // 獲取欄位的值 name = cur.getString(cur.getColumnIndex(People.NAME)); phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER)); Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show(); } while (cur.moveToNext()); } } }
從上面的例項我們可以得到以下幾點:
(1)訪問Content Provider需要一定的操作許可權;
(2)訪問Content Prvider需要使用到ContentResolver物件;
(3)ContentResolver支援query,insert,delete,update操作;
(4)由URI確定Content Provider中要操作的具體資料;
(5)insert時,要新增的資料可以使用ContentValues封裝。