Android學習筆記37:使用Content Providers方式共用資料

來源:互聯網
上載者:User

  在Android中一共提供了5種資料存放區方式,分別為:

  (1)Files:通過FileInputStream和FileOutputStream對檔案進行操作。具體使用方法可以參閱博文《Android學習筆記34:使用檔案儲存體資料》。

  (2)Shared Preferences:常用來儲存索引值對形式的資料,對系統配置資訊進行儲存。具體使用方法可以參閱博文《Android學習筆記35:使用Shared Preferences方式儲存資料》。

  (3)Content Providers:資料共用,用於應用程式之間資料的訪問。

  (4)SQLite:Android內建的輕量級關係型資料庫,支援SQL語言,用來儲存大量的資料,並且能夠對資料進行使用、更新、維護等操作。具體使用方法可以參閱博文《Android學習筆記36:使用SQLite方式儲存資料》。

  (5)Network:通過網路來儲存和擷取資料。

  本篇博文介紹第三種方式,通過Content Providers實現應用程式之間的資料共用。

 

1.Content Providers簡介

  在Android系統中,不存在一個公用的資料存放區區供所有的應用程式訪問,也就是說資料在各個應用程式中是私人的。那麼,如何在一個應用程式中訪問另一個應用程式中的資料,實現應用程式之間的資料共用呢?

  當然,你可以通過《Android學習筆記34:使用檔案儲存體資料》一文中講到的設定openFileOutput()方法中的第二個參數mode為Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE,讓別的應用程式可以讀寫該應用程式中的檔案。但是,使用這種方式的弊端也是顯而易見的,不僅需要知道該檔案的儲存路徑,而且會將該檔案內容完全的暴露出去,對於內容提供者和內容訪問者來說都是不方便和不安全的。

  為此,Android系統提供了Content Providers,用以方便安全的實現應用程式間的資料共用。

1.1ContentResolver

  所有的Content Providers都會實現一些共同的介面,包括資料的查詢、添加、更改和刪除。在應用程式中,我們可以通過使用getContentResolver()方法來取得一個ContentResolver對象,然後就可以通過這個ContentResolver對象來操作你需要的Content Provider了。ContentResolver類提供的用來操作Content Provider的方法主要有insert()、delete()、update()和query()。

  通常,對於開發人員而言,並不需要同Content Provider對象直接打交道。系統運行時,會將所有的ContentProvider對象執行個體化,對於每一種類型的ContentProvider只有一個執行個體。這個執行個體可以與在不同的程式或進程中的多個ContentResolver對象進行通訊。而這些進程間的互動則是由ContentResolver和ContentProvider類進行處理的。

  對於Content Providers而言,最重要的就是資料存放區結構和URI。

1.2資料存放區結構

  Content Providers將其儲存的資料以資料表的形式提供給訪問者,在資料表中,每一行為一條記錄,每一列為具有特定類型和意義的資料。比如,連絡人的Content Provider資料存放區結構1所示。

圖1 Content Provider資料存放區結構樣本

  可以看出,每條記錄都有一個_ID欄位用來唯一的標識該記錄,類似於資料庫中的主鍵。

1.3URI

  每一個Content Provider都對外提供一個能夠唯一標識自己資料集的公開URI,如果一個Content Provider管理多個資料集,則需要為每一個資料集都分配一個獨立的URI。

  Android規定,所有Content Provider的URI都必須以“content://”開頭。通常,URI由3部分組成:“content://”、資料的路徑、標識ID(可選)。

  比如,以下是系統提供的一些URI:

  (1)content://media/internal/images

  (2)content://contacts/people/2

  (3)content://contacts/people

  其中,(1)將返回裝置上儲存的所有圖片;(2)將返回連絡人資訊中ID為5的連絡人記錄;(3)將返回裝置上所有的連絡人資訊。

  每個ContentResolver對象都將URI作為其第一個參數,URI決定了ContentResolver將與哪一個Content Provider對話。

 

2.擷取Content Provider內容

  Android系統為一些常見的資料類型(如音頻、視頻、映像、通訊錄連絡人等)內建了一系列的Content Provider。以下就以通訊錄連絡人為例,講講如何擷取Content Provider內容。

  首先,我們需要在模擬器中運行“連絡人”應用程式程式,並在其中新增連絡人...。2所示。

圖2 新增連絡人...

  2所示,我在“連絡人”應用程式程式中添加了兩個連絡人:李明和王磊。

  然後,我們需要建立一個自己的工程,該工程的主要功能就是得到持有連絡人資訊的Content Provider中的資料。這裡,我在布局檔案中定義了一個TextView控制項,用來將獲得的連絡人資料顯示出來,運行後的效果3所示。

圖3 擷取Content Provider內容

  由圖3可以看出,我們自己建立的應用程式確實從“連絡人”應用程式程式中獲得了資料(ID和Name欄位),當然,如果你需要,你可以擷取圖1中的更多的欄位資訊。

  下面的代碼給出了實現這一功能的一種方案。

 1     /* 2      * Function  :    擷取連絡人清單資訊 3      * Author    :    部落格園-依舊淡然 4      */ 5     public String getResult() { 6          7         String result = ""; 8         Uri uri = Uri.parse("content://contacts/people");        //連絡人Content Provider的URI 9         String[] columns = {People._ID, People.NAME};            //連絡人的ID和Name10         11         ContentResolver contentResolver = getContentResolver();     //擷取ContentResolver對象12         Cursor cursor = contentResolver.query(uri, columns, null, null, null);    //查詢Content Provider13             int peopleId = cursor.getColumnIndex(People._ID);       //獲得ID欄位的列索引14             int peopleName = cursor.getColumnIndex(People.NAME);    //獲得Name欄位的列索引15             16         //遍曆Cursor對象,提取資料17         for(cursor.moveToFirst(); (!cursor.isAfterLast()); cursor.moveToNext()) {18             result = result + cursor.getString(peopleId) + "\t\t";19             result = result + cursor.getString(peopleName) + "\t\n";20         }21         cursor.close();22         return result;23     }

  通過以上的代碼可以看出,要擷取Content Provider內容,我們需要知道Content Provider的URI以及Content Provider的資料存放區形式(欄位名稱和欄位類型)。然後,我們便可以通過使用ContentResolver對象的query()方法對Content Provider進行查詢了,查詢的結果需要使用CursorObject Storage Service(有關Cursor的介紹可以參閱《Android學習筆記36:使用SQLite方式儲存資料》一文)。最後遍曆Cursor對象,取出各個欄位的資訊即可。

  因為該應用程式需要訪問連絡人資訊,所以還需要在AndroidManifest.xml檔案中加入相應的許可權許可,具體如下:

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

  至此,我們便完成了擷取連絡人Content Provider內容的功能。

 

3.提供Content Provider內容

  上面介紹了如何從別的應用程式中擷取Content Provider內容,那麼如何在自己的應用程式中提供Content Provider內容供別的應用程式訪問呢?

  一般來說,讓自己的資料被別的應用程式訪問有兩種方式:建立自己的Content Provider(即繼承自Content Provider的子類),或者是將自己的資料加入到已有的Content Provider中去。將自己的資料加入到已有的Content Provider中去有一定的局限性,因為要保證自己的資料和現有的Content Provider資料類型相同,並且具有該Content Provider的寫入許可權。

  下面將說說如何建立一個自己的Content Provider,大致可以分為3個步驟。

3.1建立資料的儲存系統

  很顯然,要將自己應用程式中的資料共用給他人,肯定需要建立自己的資料存放區系統。當然了,選擇什麼樣的儲存系統(檔案儲存體系統、SQLite資料庫等)完全由開發人員決定。

  在《Android學習筆記36:使用SQLite方式儲存資料》一文中,我們搭建了一個簡單的SQLite資料庫系統。在該資料庫中,我們建立了一張具有3個欄位(studentId、studentName、studentAge)的表,用來儲存學生資訊。

  這裡,我們就以該工程為例,講講如何將該工程中的學生資訊通過Content Provider方式共用出去。

3.2擴充Content Provider類

  在該工程中,我們需要建立了一個繼承自ContentProvider的類。用來將要共用的資料進行封裝並以ContentResolver對象和Cursor對象能夠訪問的形式對外展示。這裡,我將這個類命名為了“StudentContentProvider”。

  在ContentProvider類中提供了6個抽象方法,分別為:

  (1)public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);

  (2)public abstract Uri insert (Uri uri, ContentValues values);

  (3)public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs);

  (4)public abstract int delete (Uri uri, String selection, String[] selectionArgs);

  (5)public abstract String getType (Uri uri);

  (6)public abstract boolean onCreate ();

  其中,query()方法用於將查詢到的資料以Cursor對象的形式返回;insert()方法用於向Content Provider中插入新資料記錄,該方法中的第二個參數ContentValues對象表示資料記錄的列名和列值的映射;update()方法用於更新Content Provider中的已存在的資料記錄;delete()方法用於從Content Provider中刪除資料記錄;getType()方法用於返回Content Provider中資料的(MIME)類型;onCreate()方法當Content Provider啟動時被調用。

  以上的6個方法將會在ContentResolver對象中被調用,所以很好的實現這些抽象方法就會為ContentResolver提供一個完善的外部介面。

  當然了,你可以根據自己應用程式的需要,有選擇的實現上述6個方法,比如,你可以只實現query()方法,這樣別的應用程式就自能對你提供的Content Provider進行查詢操作,而無法對你提供的Content Provider進行添加、刪除等操作,從而保證了資料的安全性。

  如下的代碼實現了query()方法。

1     /*2      * Function  :    查詢方法3      * Author    :    部落格園-依舊淡然4      */5     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {6         db = mySQLiteOpenHelper.getWritableDatabase();7         Cursor cursor = db.query("tab_student", projection, selection, selectionArgs, null, null, sortOrder);8         return cursor;9     }

  可以看出,查詢的核心其實還是調用SQLiteDatabase類提供的query()方法,將查詢到的結果儲存在Cursor對象中,最後直接將Cursor對象返回即可。

  此外,在繼承自ContentProvider類的“StudentContentProvider”中,我們還需要做一件很重要的事,那就是指定Content Provider的URI。該URI必須是唯一的,不能和系統的URI相同,更不能與其他應用程式提供的Content Provider的URI相同。

  這裡我定義了Content Provider的URI為“content://com.example.sqlite.studentProvider/student”。

3.3聲明Content Provider的許可權

  建立好的Content Provider必須在應用程式的AndroidManifest.xml檔案中進行聲明,否則,該Content Provider對於Android系統是不可見的。

  具體的聲明方式如下:

1     <!-- 聲明內容提供者 -->2     <provider                    
      android:name="com.example.android_datastorage_sqlite.provider.StudentContentProvider"3 android:authorities="com.example.sqlite.studentProvider" >4 </provider>

  其中,<provider></provider>標籤位於<application></application>標籤下。android:name屬性用於指明StudentContentProvider的全稱類名,android:authorities屬性唯一的標識了一個Content Provider。

  至此,我們便在該工程中建立了自己的Content Provider,並提供了query()方法供別的應用程式查詢該工程中的SQLite資料表。

3.4驗證

  在應用程式Android_DataStorage_SQLite的SQLite資料表中,我們添加了3條記錄,4所示。


圖4 SQLite資料表資訊

  建立一個應用程式Android_DataStorage_ContentProviders,用來擷取自訂的Content Provider內容。擷取自訂的Content Provider內容的方法,和前面講的擷取連絡人應用程式的Content Provider內容的方法類似。使用自訂的Content Provider的URI,並查詢資料表中相應的欄位即可。可以看到查詢到的資訊5所示。

圖5 查詢自訂的Content Provider內容

  可以看出,在應用程式Android_DataStorage_ContentProviders中確實訪問到了應用程式Android_DataStorage_SQLite中的資料表資訊,通過Content Provider方式實現了資料在應用程式之間的共用。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.