Android ContentResolver使用說明
Android是如何實現(xiàn)應用程序之間數(shù)據(jù)共享的?一個應用程序可以將自己的數(shù)據(jù)完全暴露出去,外界更本看不到,也不用看到這個應用程序暴露的數(shù)據(jù)是如何存儲的,或者是使用數(shù)據(jù)庫還是使用文件,還是通過網(wǎng)上獲得,這些一切都不重要,重要的是外界可以通過這一套標準及統(tǒng)一的接口和這個程序里的數(shù)據(jù)打交道,例如:添加(insert)、刪除(delete)、查詢(query)、修改(update),當然需要一定的權限才可以。
如何將應用程序的數(shù)據(jù)暴露出去? Android提供了ContentProvider,一個程序可以通過實現(xiàn)一個Content provider的抽象接口將自己的數(shù)據(jù)完全暴露出去,而且Content providers是以類似數(shù)據(jù)庫中表的方式將數(shù)據(jù)暴露。Content providers存儲和檢索數(shù)據(jù),通過它可以讓所有的應用程序訪問到,這也是應用程序之間唯一共享數(shù)據(jù)的方法。要想使應用程序的數(shù)據(jù)公開化,可通過2種方法:創(chuàng)建一個屬于你自己的Content provider或者將你的數(shù)據(jù)添加到一個已經(jīng)存在的Content provider中,前提是有相同數(shù)據(jù)類型并且有寫入Content provider的權限。
如何通過一套標準及統(tǒng)一的接口獲取其他應用程序暴露的數(shù)據(jù)?Android提供了ContentResolver,外界的程序可以通過ContentResolver接口訪問ContentProvider提供的數(shù)據(jù)。
當前篇主要說明,如何獲取其它應用程序共享的數(shù)據(jù),比如獲取Android 手機電話薄中的信息。
什么是URI?
在學習如何獲取ContentResolver前,有個名詞是必須了解的:URI。URI是網(wǎng)絡資源的定義,在Android中賦予其更廣闊的含義。
將其分為A,B,C,D 4個部分:
A:標準前綴,用來說明一個Content Provider控制這些數(shù)據(jù),無法改變的;
B:URI的標識,它定義了是哪個Content Provider提供這些數(shù)據(jù)。對于第三方應用程序,為了保證URI標識的唯一性,它必須是一個完整的、小寫的 類名。這個標識在<provider> 元素的 authorities屬性中說明:
<provider name=”.TransportationProvider” authorities=”com.example.transportationprovider” . . . >
C:路徑,Content Provider使用這些路徑來確定當前需要生什么類型的數(shù)據(jù),URI中可能不包括路徑,也可能包括多個;
D:如果URI中包含,表示需要獲取的記錄的ID;如果沒有ID,就表示返回全部;
由于URI通常比較長,而且有時候容易出錯,切難以理解。所以,在Android當中定義了一些輔助類,并且定義了一些常量來代替這些長字符串,例如:People.CONTENT_URI
ContentResolver 介紹說明
看完這些介紹,大家一定就明白了,ContentResolver是通過URI來查詢ContentProvider中提供的數(shù)據(jù)。除了URI以外,還必須知道需要獲取的數(shù)據(jù)段的名稱,以及此數(shù)據(jù)段的數(shù)據(jù)類型。如果你需要獲取一個特定的記錄,你就必須知道當前記錄的ID,也就是URI中D部分。
前面也提到了Content providers是以類似數(shù)據(jù)庫中表的方式將數(shù)據(jù)暴露出去,那么ContentResolver也將采用類似數(shù)據(jù)庫的操作來從Content providers中獲取數(shù)據(jù)。現(xiàn)在簡要介紹ContentResolver的主要接口,如下:
返回值 | 函數(shù)聲明 |
final Uri | insert(Uri url, ContentValues values)Inserts a row into a table at the given URL. |
final int | delete(Uri url, String where, String[] selectionArgs)Deletes row(s) specified by a content URI. |
final Cursor | query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)Query the given URI, returning a Cursor over the result set. |
final int | update(Uri uri, ContentValues values, String where, String[] selectionArgs)Update row(s) in a content URI. |
看到這里,是否感覺與數(shù)據(jù)庫的操作基本一樣的?就是這樣的,詳細解析請參考了 Android SQLite解析 中的說明,不在此詳細說明。
最后一個問題:如何獲取ContentResolver?調用getContentResolver (),例如:ContentResolver cr = getContentResolver();
知道ContentResolver是通過ContentProvider來獲取其他與應用程序共享的數(shù)據(jù),那么ContentResolver與ContentProvider的接口應該差不多的。
其中ContentProvider負責
* 組織應用程序的數(shù)據(jù);
* 向其他應用程序提供數(shù)據(jù);
ContentResolver則負責
* 獲取ContentProvider提供的數(shù)據(jù);
* 修改/添加/刪除更新數(shù)據(jù)等;
ContentProvider 是如何向外界提供數(shù)據(jù)的?
Android提供了ContentProvider,一個程序可以通過實現(xiàn)一個ContentProvider的抽象接口將自己的數(shù)據(jù)完全暴露出去,而且ContentProviders是以類似數(shù)據(jù)庫中表的方式將數(shù)據(jù)暴露,也就是說ContentProvider就像一個“數(shù)據(jù)庫”。那么外界獲取其提供的數(shù)據(jù),也就應該與從數(shù)據(jù)庫中獲取數(shù)據(jù)的操作基本一樣,只不過是采用URI來表示外界需要訪問的“數(shù)據(jù)庫”。至于如何從URI中識別出外界需要的是哪個“數(shù)據(jù)庫”,這就是Android底層需要做的事情了,不在此詳細說。簡要分析下ContentProvider向外界提供數(shù)據(jù)操作的接口:
query(Uri, String[], String, String[], String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
這些操作與數(shù)據(jù)庫的操作基本上完全一樣,在此不詳細說,具體的解析可以參考 Android Sqlite解析 中的詳細說明。需要特殊說明的地方是URI:
在URI的D部分可能包含一個_ID ,這個應該出現(xiàn)在SQL語句中的,可以以種特殊的方式出現(xiàn),這就要求我們在提供數(shù)據(jù)的時候,需要來額外關注這個特殊的信息。Android SDK推薦的方法是:在提供數(shù)據(jù)表字段中包含一個ID,在創(chuàng)建表時INTEGER PRIMARY KEY AUTOINCREMENT標識此ID字段。
ContentProvider 是如何組織數(shù)據(jù)的?
組織數(shù)據(jù)主要包括:存儲數(shù)據(jù),讀取數(shù)據(jù),以數(shù)據(jù)庫的方式暴露數(shù)據(jù)。數(shù)據(jù)的存儲需要根據(jù)設計的需求,選擇合適的存儲結構,首選數(shù)據(jù)庫,當然也可以選擇本地其他文件,甚至可以是網(wǎng)絡上的數(shù)據(jù)。數(shù)據(jù)的讀取,以數(shù)據(jù)庫的方式暴露數(shù)據(jù)這就要求,無論數(shù)據(jù)是如何存儲的,數(shù)據(jù)最后必須以數(shù)據(jù)的方式訪問。
可能還有2個問題,是需要關注的。
1. ContentProvider是什么時候創(chuàng)建的,是誰創(chuàng)建的?訪問某個應用程序共享的數(shù)據(jù),是否需要啟動這個應用程序?這個問題在 Android SDK中沒有明確說明,但是從數(shù)據(jù)共享的角度出發(fā),ContentProvider應該是Android在系統(tǒng)啟動時就創(chuàng)建了,否則就談不上數(shù)據(jù)共享了。這就要求在AndroidManifest.XML中使用<provider>元素明確定義。
2. 可能會有多個程序同時通過ContentResolver訪問一個ContentProvider,會不會導致像數(shù)據(jù)庫那樣的“臟數(shù)據(jù)”?這個問題一方面需要數(shù)據(jù)庫訪問的同步,尤其是數(shù)據(jù)寫入的同步,在AndroidManifest.XML中定義ContentProvider的時候,需要考慮是<provider>元素multiprocess屬性的值;另外一方面Android在ContentResolver中提供了 notifyChange()接口,在數(shù)據(jù)改變時會通知其他ContentObserver,這個地方應該使用了觀察者模式,在 ContentResolver中應該有一些類似register,unregister的接口。
至此,已經(jīng)對ContentProvider提供了比較全面的分析,至于如何創(chuàng)建ContentProvider,可通過2種方法:創(chuàng)建一個屬于你自己的ContentProvider或者將你的數(shù)據(jù)添加到一個已經(jīng)存在的ContentProvider中,當然前提是有相同數(shù)據(jù)類型并且有寫入 Content provider的權限。在Android SDK的sample中提供的 Notepad具體實例 中去看源代碼!
制作ContentResolver實例
以上就完全介紹了如何獲取、使用ContentResolver,啟動Eclipes,制作一個完整的實例如下:
打開showcontent.java,修改如下:
package moandroid.showcontact; import android.app.ListActivity; import android.database.Cursor; import android.os.Bundle; import android.provider.Contacts.Phones; import android.widget.ListAdapter; import android.widget.SimpleCursorAdapter; public class showcontact extends ListActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Cursor c = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null); startManagingCursor(c); ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, c, new String[] { Phones.NAME, Phones.NUMBER }, new int[] { android.R.id.text1, android.R.id.text2 }); setListAdapter(adapter); } }
然后在AndroidManifest.XML中<application>元素前增加如下許可:
<uses-permission android:name=”android.permission.READ_CONTACTS” />
最后運行程序,在模擬器啟動后,單擊Menu返回到Home界面,打開Contacts選擇Contacts標簽頁,添加2個聯(lián)系人信息。返回到Home,選擇moandroid.showcontact運行,剛添加的2個聯(lián)系人信息將顯示在界面上,如下:
總結說明
ContentResolver的使用極大的方便了應用程序之間共享數(shù)據(jù),如何將應用程序的數(shù)據(jù)完全暴露給給他應用程序使用了
android中ContentResolver的使用
使用ContentResolver增刪改查電話本信息,詳細代碼如下:
import android.app.ListActivity; import android.content.ContentValues; import android.database.Cursor; import android.os.Bundle; import android.provider.Contacts.People; import android.support.v4.widget.SimpleCursorAdapter; import android.widget.ListAdapter; public class MainActivity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); insert("tester1"); update("tester2", new String(People.NAME + "='tester1'")); delete(new String(People.NAME + "='tester2'")); select(); } /* * 向聯(lián)系人列表中插入新的聯(lián)系人 * @param name The value of People.NAME */ public void insert(String name) { ContentValues ct = new ContentValues(); ct.put(People.NAME, name); getContentResolver().insert(People.CONTENT_URI, ct); } /* * 更新手機中指定的聯(lián)系人 * @param name A new name for People.NAME * @param where The update requirement. */ public void update(String name, String where) { ContentValues ct = new ContentValues(); ct.put(People.NAME, name); getContentResolver().update(People.CONTENT_URI, ct, where, null); } /* * 刪除手機中指定的聯(lián)系人 * @param where The delete requirement. */ public void delete(String where) { getContentResolver().delete(People.CONTENT_URI, where, null); } // 查找所有聯(lián)系人 public void select() { Cursor cursor = getContentResolver().query(People.CONTENT_URI, new String[] { People._ID, People.NAME }, null, null, null); ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, new String[] { People.NAME }, new int[] { android.R.id.text1 }); setListAdapter(adapter); } }
AndroidManifest.xml中添加如下權限:
<uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
相關文章
Android自定義StickinessView粘性滑動效果
這篇文章主要為大家詳細介紹了Android自定義StickinessView粘性滑動效果的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03Android UI系列-----ScrollView和HorizontalScrollView的詳解
本篇文章主要是介紹的Android UI系列-----ScrollView和HorizontalScrollView,ScrollView和HorizontalScrollView都是布局容器,有需要的可以了解一下。2016-11-11Android實現(xiàn)Tab布局的4種方式(Fragment+TabPageIndicator+ViewPager)
Android現(xiàn)在實現(xiàn)Tab類型的界面方式越來越多,本文詳細介紹了Android實現(xiàn)Tab布局的4種方式,具有一定的參考價值,有興趣的可以了解一下。2016-11-11Android編程實現(xiàn)將時間轉化成幾分鐘前、幾天前等形式的工具類
這篇文章主要介紹了Android編程實現(xiàn)將時間轉化成幾分鐘前、幾天前等形式的工具類,涉及Android針對日期時間的相關運算與判斷簡單操作技巧,需要的朋友可以參考下2018-02-02