第八章:四大元件之Content Provider

自助者天助發表於2014-12-02

前言

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>
View Code

 

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>
View Code

新增記錄:
要增加記錄,我們可以呼叫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);
}
View Code

刪除記錄:
Content Provider中的getContextResolver.delete()方法可以用來刪除記錄,下面的記錄用來刪除裝置上所有的聯絡人資訊:

private void deleteRecords() {
    Uri uri = People.CONTENT_URI;
    getContentResolver().delete(uri, null, null);
}
View Code

修改記錄:
我們可以使用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);
}
View Code

查詢記錄

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());
       }
    }
}
View Code

 

從上面的例項我們可以得到以下幾點:

(1)訪問Content Provider需要一定的操作許可權;

(2)訪問Content Prvider需要使用到ContentResolver物件;

(3)ContentResolver支援query,insert,delete,update操作;

(4)由URI確定Content Provider中要操作的具體資料;

(5)insert時,要新增的資料可以使用ContentValues封裝。

相關文章