Content Providers內容提供者

 

Content Providers內容提供者
 
 
In this document本文檔
1.  Content provider basics 內容提供者基礎
2.  Querying a content provider 查詢內容提供者
3.  Modifying data in a provider 修改內容提供者數據
4.  Creating a content provider 建立內容提供者
5.  Content URI summary 內容URI總結
Key classes關鍵類
1.  ContentProvider 內容提供者
2.  ContentResolver 內容解釋者
3.  Cursor 指示器(指針)
See also
1.  Calendar Provider 日曆提供者
Content providers store and retrieve data and make it accessible to all applications. They're the only way to share data across applications; there's no common storage area that all Android packages can access.
內容提供者存儲和取回數據,並讓全部的應用能夠訪問它.它是應用之間惟一共享數據的方法.系統中沒有全部應用均可以訪問的通用存儲區域.
Android ships with a number of content providers for common data types (audio, video, p_w_picpaths, personal contact information, and so on). You can see some of them listed in the android.provider package. You can query these providers for the data they contain (although, for some, you must acquire the proper permission to read the data).
Android帶有大量普通數據的內容提供者(音樂,視頻,圖像,我的通訊錄信息,等等).你能夠在 android.provider 包中看到.你能夠內容提供者所包含的數據(可是,對於某些數據,你須要取得相應的數據讀取權限)
Note: Android 4.0 introduces the Calendar Provider. For more information, see Calendar Provider.注意4.0包括了日曆提供者,詳細狀況,請看 Calendar Provider
If you want to make your own data public, you have two options: You can create your own content provider (a ContentProvider subclass) or you can add the data to an existing provider — if there's one that controls the same type of data and you have permission to write to it.
若是你想讓公開你的數據,你有兩個選擇:你能夠建立本身的內空提供者(一個 ContentProvider 子類),或者把數據加入到已存在的內空提供者— (若是有一個)控制數據的一樣的類型並你有權限寫入它.(很差翻譯)
This document is an introduction to using content providers. After a brief discussion of the fundamentals, it explores how to query a content provider, how to modify data controlled by a provider, and how to create a content provider of your own.
本文檔是使用內容提供者的介紹.在簡短的討論基礎以後,它展現了怎樣查詢內容提供者,修改由內容提供控制的數據,及如何建立本身的內容提供者.
Content Provider Basics內容提供者基礎
How a content provider actually stores its data under the covers is up to its designer. But all content providers implement a common interface for querying the provider and returning results — as well as for adding, altering, and deleting data.
設計者決定內容提供者如何在掩護下實際的存儲他的數據.可是內容提供者實現一個通用接口來查詢內容提供者並返回結果—好比增長,更改,及刪除
It's an interface that clients use indirectly, most generally through ContentResolver objects. You get a ContentResolver by calling getContentResolver() from within the implementation of an Activity or other application component:
它是一個用戶間接使用的接口,大多狀況是經過一個 ContentResolver 對象. 你能夠在活動的實現或者其餘應用組件, 調用getContentResolver() 方法, 獲得一個內容解釋者.
ContentResolver cr = getContentResolver();
You can then use the ContentResolver's methods to interact with whatever content providers you're interested in.
而後,你能夠用這個內容解釋者的方法,與你想要的內容提供者交互.
When a query is initiated, the Android system identifies the content provider that's the target of the query and makes sure that it is up and running. The system instantiates all ContentProvider objects; you never need to do it on your own. In fact, you never deal directly with ContentProvider objects at all. Typically, there's just a single instance of each type of ContentProvider. But it can communicate with multiple ContentResolver objects in different applications and processes. The interaction between processes is handled by the ContentResolver and ContentProvider classes.
當一個查詢被實例化,Android系統肯定查詢的目標,即內容提供者,並確保它是運行的.系統實例化全部的內容提供者對象.你永遠不須要本身初始化.事實上,你從不直接處理內容提供者對象.典型的,是每一個內容提供者的單個實例.可是它能夠在不一樣應用和進程中與多個內容解釋者難通訊.在進之間的交流是由內容解釋者和內容提供者的類來處理的.
The data model數據模型
Content providers expose their data as a simple table on a database model, where each row is a record and each column is data of a particular type and meaning. For example, information about people and their phone numbers might be exposed as follows:
內容提供者把它的數解釋成一個基於數據庫模型上的簡單的表格,每一行是一條記錄,每一列是特定類型的數據和它所表示的意義.好比,一個關於人和他的電話號碼的表格多是下面這個樣子:

_ID
NUMBER
NUMBER_KEY
LABEL
NAME
TYPE
13
(425) 555 6677
425 555 6677
Kirkland office
Bully Pulpit
TYPE_WORK
44
(212) 555-1234
212 555 1234
NY apartment
Alan Vain
TYPE_HOME
45
(212) 555-6657
212 555 6657
Downtown office
Alan Vain
TYPE_MOBILE
53
201.555.4433
201 555 4433
Love Nest
Rex Cars
TYPE_HOME

Every record includes a numeric _ID field that uniquely identifies the record within the table. IDs can be used to match records in related tables — for example, to find a person's phone number in one table and pictures of that person in another.
每一個記錄標有_ID的域,是表格中該數據惟一的標識.在關係表中,IDs經常使用於匹配記錄—例如,在表中找出某我的的電話號碼,及他的照片.
A query returns a Cursor object that can move from record to record and column to column to read the contents of each field. It has specialized methods for reading each type of data. So, to read a field, you must know what type of data the field contains. (There's more on query results and Cursor objects later.)
一個查詢返回一個 Cursor 對象, 該對象能夠從一個記錄移動到另外一個記錄, 而且能夠列的形式讀取每一個域的內容. 它有讀取每種數據類型的特殊方法. 因此, 要讀取一個域, 你必須知道該域包括的數據是什麼類型.( 後面有更多關於Cursor 對象和查詢結果的討論)
URIs
Each content provider exposes a public URI (wrapped as a Uri object) that uniquely identifies its data set. A content provider that controls multiple data sets (multiple tables) exposes a separate URI for each one. All URIs for providers begin with the string " content://". The content: scheme identifies the data as being controlled by a content provider.
每一個內容提供者顯示一個公用的URI(當作一個 Uri 對象包裹起來),它是數據集的標識.一個內容提供者控制多個數據集合(多個表格),並把每個解釋成一個獨立的URI.內容提供者的全部的URIs都以字串" content://"開始。內容:cheme identifies the data as being controlled by a content provider.
If you're defining a content provider, it's a good idea to also define a constant for its URI, to simplify client code and make future updates cleaner. Android defines CONTENT_URI constants for all the providers that come with the platform. For example, the URI for the table that matches phone numbers to people and the URI for the table that holds pictures of people (both controlled by the Contacts content provider) are:
若是你定義一個內容提供者,最好爲它定義一人URI常量,以指定客戶代碼併爲未來更新清除。Android爲平臺自帶的全部內容提供者定義了 CONTENT_URI 常量.好比,匹配某人電話的表格的URI,匹配某人所捅有的圖片的URI(它們都由內通訊錄內容提供者所控制)
android.provider.Contacts.Phones.CONTENT_URI android.provider.Contacts.Photos.CONTENT_URI
The URI constant is used in all interactions with the content provider. Every ContentResolver method takes the URI as its first argument. It's what identifies which provider the ContentResolver should talk to and which table of the provider is being targeted.
這個URI經常使用於與內容提供者進行全部的交互。每一個 ContentResolver 方法,都把它當成第一個參數。它指定了內容解釋者與那個內容提供者對話,內容提供者定位到那個表格。
Querying a Content Provider查詢內容提供者
You need three pieces of information to query a content provider: 要查詢一個內容提供者,你須要三個方面的信息
·         The URI that identifies the provider 指定提供者的URI
·         The names of the data fields you want to receive 你想要接收的數據域名字
·         The data types for those fields 這些域的數據類型。
If you're querying a particular record, you also need the ID for that record.若是你要查詢一個特定記錄,你還須要該記錄的ID.
Making the query生成查詢
To query a content provider, you can use either the ContentResolver.query() method or the Activity.managedQuery() method. Both methods take the same set of arguments, and both return a Cursor object. However, managedQuery() causes the activity to manage the life cycle of the Cursor. A managed Cursor handles all of the niceties, such as unloading itself when the activity pauses, and requerying itself when the activity restarts. You can ask an Activity to begin managing an unmanaged Cursor object for you by calling Activity.startManagingCursor().
要查詢內容提供者。你能夠用 ContentResolver.query()方法,或者 Activity.managedQuery()方法。它們都採用同相樣的參數集,並都返回一個Cursor對象。可是,方法致使活動管理Cursor的生命週期。一個管理的Cursor處理全部的細節,好比當活動暫停時不加載它本身,當活動從新啓動時,從新查詢它本身。你能夠調用 Activity.startManagingCursor()方法,要求活動管理沒有管理的Cursor對象。
The first argument to either query() or managedQuery() is the provider URI — the CONTENT_URI constant that identifies a particular ContentProvider and data set (see URIs earlier).
query() 或者 managedQuery() 方法的,第一個參數是URI,標識某個內容提供者及數據集的 CONTENT_URI 常量.
To restrict a query to just one record, you can append the _ID value for that record to the URI — that is, place a string matching the ID as the last segment of the path part of the URI. For example, if the ID is 23, the URI would be:
爲了限定一個查詢僅查詢一個記錄,你能夠給URI追加一個_ID值—放置一個匹配ID字串,作爲URI部分的最後路徑段。
content://. . . ./23
There are some helper methods, particularly ContentUris.withAppendedId() and Uri.withAppendedPath(), that make it easy to append an ID to a URI. Both are static methods that return a Uri object with the ID added. So, for example, if you were looking for record 23 in the database of people contacts, you might construct a query as follows:
有一些輔助方法,特別是 ContentUris.withAppendedId() 方法和 Uri.withAppendedPath()方法,它們使得追加ID到URI更加容易。它們都是靜態方法,而且返回一個帶追加ID的Uri對象。因此若是,你要在通訊錄數據庫中查詢記錄23,你可能會這樣構建一個查詢:
import android.provider.Contacts.People;
import android.content.ContentUris;
import android.net.Uri;
import android.database.Cursor;
 
// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
//使用方法,產生一個基於Uri且通訊錄_ID等於23的。
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
 
// Alternatively, use the Uri method to produce the base URI.
// It takes a string rather than an integer.
// 一個可選方法,用Uri方法,產生一個基於URI的,它採用字串,而不是一個整型值
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
 
// Then query for this specific record:查詢這個指定的記錄:
Cursor cur = managedQuery(myPerson, null, null, null, null);
The other arguments to the query() and managedQuery() methods delimit the query in more detail. They are:
query()managedQuery() 方法的,其餘參數,更詳細的限定查詢內容:
·         The names of the data columns that should be returned. A null value returns all columns. Otherwise, only columns that are listed by name are returned. All the content providers that come with the platform define constants for their columns. For example, the android.provider.Contacts.Phones class defines constants for the names of the columns in the phone table illustrated earlier — _ID, NUMBER, NUMBER_KEY, NAME, and so on.
應該返回數據列的名字。一個null值,返回全部列。不然,只有由名字指定的列被返回。平臺的全部內容提供者,爲它們的列定義了常量。好比 android.provider.Contacts.Phones 定義了上電話面圖表中的列名的常量 —ID, NUMBER, NUMBER_KEY, NAME, 等等。
·         A filter detailing which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). A null value returns all rows (unless the URI limits the query to a single record).
還有過濾到那一行要返回,格式化似一個SQL WHERE簇(包括WHERE本身),null返回所的行(除非URI限定了查詢單個記錄)
·         Selection arguments.選擇參數
·         A sorting order for the rows that are returned, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). A null value returns the records in the default order for the table, which may be unordered.
返回行的排列順序,以簇格式化似SQL ORDER(包括 ORDER BY 它本身),一個空值返回表格中記錄的默認順序,多是無序的。
Let's look at an example query to retrieve a list of contact names and their primary phone numbers: 讓咱們看一個,查詢讀取通訊錄名字和它的主要電話號碼的列表:
import android.provider.Contacts.People;
import android.database.Cursor;
 
// Form an array specifying which columns to return. 經過一個數組指定要返回的列
String[] projection = new String[] {
                             People._ID,
                             People._COUNT,
                             People.NAME,
                             People.NUMBER
                          };
 
// Get the base URI for the People table in the Contacts content provider.
Uri contacts = People.CONTENT_URI;
 
// Make the query. 
Cursor managedCursor = managedQuery(contacts,
                         projection, // Which columns to return 要返回那些列
                         null,       // Which rows to return (all rows)返回的行(全部行)
                         null,       // Selection arguments (none)(可選參數,無)
                         // Put the results in ascending order by name(以名字降序排列)
                         People.NAME + " ASC");
This query retrieves data from the People table of the Contacts content provider. It gets the name, primary phone number, and unique record ID for each contact. It also reports the number of records that are returned as the _COUNT field of each record.
這個查詢讀取通訊錄內容提供者中人員表的數據。它讀取每一個通訊錄的名字,主要電話號碼,及惟一的記錄ID.它也報道每一個記錄的 _COUNT 域的,記錄值。
The constants for the names of the columns are defined in various interfaces — _ID and _COUNT in BaseColumns, NAME in PeopleColumns, and NUMBER in PhoneColumns. The Contacts.People class implements each of these interfaces, which is why the code example above could refer to them using just the class name.
列名的常量是以各類接口定義的- _ID_COUNT 基於 BaseColumns NAME PeopleColumns, NUMBER PhoneColumns. Contacts.People 實現了這些接口,這也是爲何上面例子代碼中只使用一個類名就能夠引用它們的緣由。
What a query returns一個查詢返回什麼
A query returns a set of zero or more database records. The names of the columns, their default order, and their data types are specific to each content provider. But every provider has an _ID column, which holds a unique numeric ID for each record. Every provider can also report the number of records returned as the _COUNT column; its value is the same for all rows.
一個查詢返回一組0值,或者更多數據記錄。列名,它們的順序,由內容提供者指定的它們的數據類型。可是每個提供者有一個_ID列,它指示了每一個記錄的惟一的ID.每一個內容提供者也報道記錄的個數,返回 _COUNT 列,它的值對全部的行都是同樣的。
Here is an example result set for the query in the previous section: 這是上面章節查詢結果集的一個例子

_ID
_COUNT
NAME
NUMBER
44
3
Alan Vain
212 555 1234
13
3
Bully Pulpit
425 555 6677
53
3
Rex Cars
201 555 4433

The retrieved data is exposed by a Cursor object that can be used to iterate backward or forward through the result set. You can use this object only to read the data. To add, modify, or delete data, you must use a ContentResolver object.
取回的數據由一個 Cursor 對象解釋,它能夠向後或向前迭代記錄集。你只能用這個對象讀取數據,要添加,修改,或者刪除數據,你必需要用一個ContentResolver 內容解釋對象。
Reading retrieved data讀取取回數據。
The Cursor object returned by a query provides access to a recordset of results. If you have queried for a specific record by ID, this set will contain only one value. Otherwise, it can contain multiple values. (If there are no matches, it can also be empty.) You can read data from specific fields in the record, but you must know the data type of the field, because the Cursor object has a separate method for reading each type of data — such as getString(), getInt(), and getFloat(). (However, for most types, if you call the method for reading strings, the Cursor object will give you the String representation of the data.) The Cursor lets you request the column name from the index of the column, or the index number from the column name.
由查詢返回的Cursor 對象,訪問結果的記錄集。若是你查詢由ID指定的記錄,這個集只包含一個值。不然,它能包含多個集(若是沒有匹配,也多是空)。你能夠讀取記錄中的指定域,但你必須知道域的記錄類型,由於Cursor對象爲每一個數據類型有一個獨立的方法-好比 getString(), getInt(), 和 getFloat().( 然而,大多數類型,若是你調用讀字串方法,Cursor 對象將給一個該數據所表示的字串值) ,Cursor 對象可以讓你從列索引讀取列名,或者從列名讀取列索引
The following snippet demonstrates reading names and phone numbers from the query illustrated earlier: 下面的代碼片段演示了讀取上面圖表中的名字和電話號碼。
import android.provider.Contacts.People;
 
private void getColumnData(Cursor cur){ 
    if (cur.moveToFirst()) {
 
        String name; 
        String phoneNumber; 
        int nameColumn = cur.getColumnIndex(People.NAME); 
        int phoneColumn = cur.getColumnIndex(People.NUMBER);
        String p_w_picpathPath; 
    
        do {
            // Get the field values
            name = cur.getString(nameColumn);
            phoneNumber = cur.getString(phoneColumn);
           
            // Do something with the values. 
            ... 
 
        } while (cur.moveToNext());
 
    }
}
If a query can return binary data, such as an p_w_picpath or sound, the data may be directly entered in the table or the table entry for that data may be a string specifying a content: URI that you can use to get the data. In general, smaller amounts of data (say, from 20 to 50K or less) are most often directly entered in the table and can be read by calling Cursor.getBlob(). It returns a byte array.
若是查詢返回二進制數據,好比圖像或者聲音,數據能直接存儲在表格中,或者表格的入點多是指定一個內容的字串:你能夠用來讀取數據的URI。一般少許的數據(20到50k之間或者更少)直接存儲在表格中,而且能夠經過調用 Cursor.getBlob()讀取。它返回一個字節數組。
If the table entry is a content: URI, you should never try to open and read the file directly (for one thing, permissions problems can make this fail). Instead, you should call ContentResolver.openInputStream() to get an InputStream object that you can use to read the data.
若是表格的入點是一個內容:URI,你應永不要直接找開並讀取文件(緣由是,權限問題可能讓其失敗)。你應該調用 ContentResolver.openInputStream() 方法,獲取一個輸入流 InputStream 對象,來讀取數據。
Modifying Data修改數據。
Data kept by a content provider can be modified by: 內容提供者保持的數據可作以下修改
·         Adding new records 增長新記錄
·         Adding new values to existing records 添加新值到存在的記錄
·         Batch updating existing records 批處理更新數據
·         Deleting records 刪除數據
All data modification is accomplished using ContentResolver methods. Some content providers require a more restrictive permission for writing data than they do for reading it. If you don't have permission to write to a content provider, the ContentResolver methods will fail.
全部的修改操做由 ContentResolver 方法完成。一些內容提供者寫入數據比讀取數據要求更多的權限。若是你沒有寫某個內容提供者的權限,ContentResolver 內容解釋方法將失敗。
Adding records添加記錄
To add a new record to a content provider, first set up a map of key-value pairs in a ContentValues object, where each key matches the name of a column in the content provider and the value is the desired value for the new record in that column. Then call ContentResolver.insert() and pass it the URI of the provider and the ContentValues map. This method returns the full URI of the new record — that is, the provider's URI with the appended ID for the new record. You can then use this URI to query and get a Cursor over the new record, and to further modify the record. Here's an example:
要添加一個記錄到內容提供者,首先要設置一個內容對象的鍵值對,每一個鍵值匹配內容提供者的列的名,和那列新記錄指望的值。而後調用方法,並傳給該方法內容提供者的URI和內容值映像。這個方法,返回新記錄的徹底URI,即該新記錄的帶有追加ID的URI.而後,你能夠用這個URI去查詢而且讓Cursor遍歷整個對象,並進一步修改該對象,這裏有一個例子:
import android.provider.Contacts.People;
import android.content.ContentResolver;
import android.content.ContentValues; 
 
ContentValues values = new ContentValues();
 
// Add Abraham Lincoln to contacts and make him a favorite.
values.put(People.NAME, "Abraham Lincoln");
// 1 = the new contact is added to favorites
// 0 = the new contact is not added to favorites
values.put(People.STARRED, 1);
 
Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
Adding new values添加新值
Once a record exists, you can add new information to it or modify existing information. For example, the next step in the example above would be to add contact information — like a phone number or an IM or e-mail address — to the new entry.
當一個記錄已經存在,你能夠給他添加新的信息或者修改存在的信息。好比,在上面的例子的下一步,將添加一個新的聯繫信息-好比電話號,或者IM,或者e-mail地址-到該新的入點。
The best way to add to a record in the Contacts database is to append the name of the table where the new data goes to the URI for the record, then use the amended URI to add the new data values. Each Contacts table exposes a name for this purpose as a CONTENT_DIRECTORY constant. The following code continues the previous example by adding a phone number and e-mail address for the record just created:
在通訊錄數據庫中增長一個新記錄的最好方法是:追加一個表示名字,where the new data goes to the URI for the record,而後用改良的URI來添加新的數據值。每一個通訊錄表爲此目的解釋成一個 CONTENT_DIRECTORY 常量。下面的例子,爲一新建立的記錄添加一個電話號和郵件地址。
Uri phoneUri = null;
Uri emailUri = null;
 
// Add a phone number for Abraham Lincoln. Begin with the URI for
// the new record just returned by insert(); it ends with the _ID
// of the new record, so we don't have to add the ID ourselves.
// Then append the designation for the phone table to this URI,
// and use the resulting URI to insert the phone number.
phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
 
values.clear();
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
values.put(People.Phones.NUMBER, "1233214567");
getContentResolver().insert(phoneUri, values);
 
// Now add an email address in the same way.
emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);
 
values.clear();
// ContactMethods.KIND is used to distinguish different kinds of
// contact methods, such as email, IM, etc. 
values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
values.put(People.ContactMethods.DATA, "test@example.com");
values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
getContentResolver().insert(emailUri, values);   
You can place small amounts of binary data into a table by calling the version of ContentValues.put() that takes a byte array. That would work for a small icon-like p_w_picpath or a short audio clip, for example. However, if you have a large amount of binary data to add, such as a photograph or a complete song, put a content: URI for the data in the table and call ContentResolver.openOutputStream() with the file's URI. (That causes the content provider to store the data in a file and record the file path in a hidden field of the record.)
你能夠調用 ContentValues.put() 方法帶字節數組的版本放置少許2 進制數據。好比,多是圖像的小icon, 或者簡短的音樂剪輯。可是,你若加大量的二進制數據,好比圖形或者完整的歌曲,放入一個內容:放數據的URI 在表格中, 調用使用文件的URI ContentResolver.openOutputStream() 方法,(這將致使內容提供者將數據存在一個文件中,而且在記錄的隱藏域記錄文件的路徑)
In this regard, the MediaStore content provider, the main provider that dispenses p_w_picpath, audio, and video data, employs a special convention: The same URI that is used with query() or managedQuery() to get meta-information about the binary data (such as, the caption of a photograph or the date it was taken) is used with openInputStream() to get the data itself. Similarly, the same URI that is used with insert() to put meta-information into a MediaStore record is used with openOutputStream() to place the binary data there. The following code snippet illustrates this convention:  
就這一點而言, MediaStore內容提供者,分發圖像,音頻和視頻數據的主要內容提供者,使用一個特別的慣例: query()方法或者managedQuery()方法使用同一個URI來獲取關於二進制數據的信息(好比:圖片標題,或者它的產生日期),它經常使用openInputStream()方法獲取數據的.一樣,該同一個URI也用於insert()插入信息到MediaStore記錄,而它一般用於openOutputStream()方法把數據放到那裏。
import android.provider.MediaStore.Images.Media;
import android.content.ContentValues;
import java.io.OutputStream;
 
// Save the name and description of an p_w_picpath in a ContentValues map. 
ContentValues values = new ContentValues(3);
values.put(Media.DISPLAY_NAME, "road_trip_1");
values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
values.put(Media.MIME_TYPE, "p_w_picpath/jpeg");
 
// Add a new record without the bitmap, but with the values just set.
// insert() returns the URI of the new record.
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
 
// Now get a handle to the file for that record, and save the data into it.
// Here, sourceBitmap is a Bitmap object representing the file to save to the database.
try {
    OutputStream outStream = getContentResolver().openOutputStream(uri);
    sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
    outStream.close();
} catch (Exception e) {
    Log.e(TAG, "exception while writing p_w_picpath", e);
}
Batch updating records批更新數據
To batch update a group of records (for example, to change "NY" to "New York" in all fields), call the ContentResolver.update() method with the columns and values to change. 經批處理一組記錄(好比,將」NY」改爲」New York」到全部的域),調用 ContentResolver.update()方法,帶上列及要改變的值。
Deleting a record刪除一個記錄
To delete a single record, call { ContentResolver.delete() with the URI of a specific row. 刪除一行,用 ContentResolver.delete()方法,帶上一個包括指定行的URI
To delete multiple rows, call ContentResolver.delete() with the URI of the type of record to delete (for example, android.provider.Contacts.People.CONTENT_URI) and an SQL WHERE clause defining which rows to delete. ( Caution : Be sure to include a valid WHERE clause if you're deleting a general type, or you risk deleting more records than you intended!).
要刪除多行,調用 ContentResolver.delete()方法,帶上一個要刪除的記錄的類型,和定義那些行的SQL WHERE簇URI(注意:若是你要刪除一個通用的類型,確保包括了一個正確的WHERE簇,不然,你可能刪除的記錄,比你想要刪除的記錄多)
Creating a Content Provider建立一個內容提供者
To create a content provider, you must: 要建立一個內容提供者,你必須:
·         Set up a system for storing the data. Most content providers store their data using Android's file storage methods or SQLite databases, but you can store your data any way you want. Android provides the SQLiteOpenHelper class to help you create a database and SQLiteDatabase to manage it. 設置存儲數據的一個系統,大多數內容提供者使用Android的文件存儲數據, 或者SQLite數據庫系統.可是你能夠以你想要的任何方法存儲數據。Android提供了一個 SQLiteOpenHelper類,幫助你建立一個數據庫,而且用 SQLiteDatabase管理它.
·         Extend the ContentProvider class to provide access to the data.繼 ContentProvider承類,來提供數據訪問。
·         Declare the content provider in the manifest file for your application (AndroidManifest.xml).在你的manifest文件中聲明內容提供者(AndroidManifest.xml)
The following sections have notes on the last two of these tasks. 下面的部分,是關於這些任務的最後兩項要注意的狀況.
Extending the ContentProvider class繼承一個內容提供者類。
You define a ContentProvider subclass to expose your data to others using the conventions expected by ContentResolver and Cursor objects. Principally, this means implementing six abstract methods declared in the ContentProvider class:
你能夠定義類的子類,用內容解釋者和Cursor對象所指望的約定,將數據解釋給其餘使用者。原則上,這意味着你要實現ContentProvider 類的,6個抽象方法。
query() insert() update() delete() getType() onCreate()
The query() method must return a Cursor object that can iterate over the requested data. Cursor itself is an interface, but Android provides some ready-made Cursor objects that you can use. For example, SQLiteCursor can iterate over data stored in an SQLite database. You get the Cursor object by calling any of the SQLiteDatabase class's query() methods. There are other Cursor implementations — such as MatrixCursor — for data not stored in a database.
query()方法,必須返回一個Cursor對象,而且它能夠迭代請求的數據。Cursor自己是一個接口.可是Android系統提供一些準備好的 Cursor對象給你使用.好比, SQLiteCursor能夠迭代存在於SQLite數據庫中的數據。你能夠調用任何一個SQLiteDatabase類的query()方法,獲得一個Cursor對象。還有一些其餘的Cursor實現,—好比 MatrixCursor—用於非數據庫存儲的數據。
Because these ContentProvider methods can be called from various ContentResolver objects in different processes and threads, they must be implemented in a thread-safe manner.
因爲這些內空提供者方法,能夠從各類內容解釋在不一樣的進程和線程調用,它們必須以線程安全的方式實現。
As a courtesy, you might also want to call ContentResolver.notifyChange() to notify listeners when there are modifications to the data. 出於好意,你可能也想調用 ContentResolver.notifyChange()方法,通知監聽器數據何時被改變了。
Beyond defining the subclass itself, there are other steps you should take to simplify the work of clients and make the class more accessible: 除了定義子類自己,還有其餘一些指定客戶端的工做步驟,以使得你的類更容易訪問。
·         Define a public static final Uri named CONTENT_URI. This is the string that represents the full content: URI that your content provider handles. You must define a unique string for this value. The best solution is to use the fully-qualified class name of the content provider (made lowercase). So, for example, the URI for a TransportationProvider class could be defined as follows:
·         定義一個叫 CONTENT_URI的公共靜態的最終的Uri.這個字串表示你的內容提供者所能處理的全部content:URI.你必須爲這個值指定一個惟一的字串,最好的解決方法是用內容提供者的全類名(由小寫構成),全部,好比,TransportationProvider的URI定義成下面的樣子:
·         public static final Uri CONTENT_URI = 
               Uri.parse("content://com.example.codelab.transportationprovider");
If the provider has subtables, also define CONTENT_URI constants for each of the subtables. These URIs should all have the same authority (since that identifies the content provider), and be distinguished only by their paths. For example:  
若是該內容提供者有子集,也要爲每一個子集定義 CONTENT_URI常量.這些URIs應都有一樣的認證(由於它標識內容提供者),而且只根據它們的路徑區分,好比:
content://com.example.codelab.transportationprovider/train content://com.example.codelab.transportationprovider/air/domestic content://com.example.codelab.transportationprovider/air/international
For an overview of content: URIs, see the Content URI Summary at the end of this document. 想要概覽content:URIs,請看本文檔後面的 Content URI Summary.
·         Define the column names that the content provider will return to clients. If you are using an underlying database, these column names are typically identical to the SQL database column names they represent. Also define public static String constants that clients can use to specify the columns in queries and other instructions.
·         定義內容提供者要返回給客戶端的列名。如要使用一個基礎數據庫,這些列名,一般表示SQL數據庫的列名。也要定義成public static字串常量,客戶端能夠在查詢或者使用其餘指令時,能夠用它指定列名。
Be sure to include an integer column named " _id" (with the constant _ID) for the IDs of the records. You should have this field whether or not you have another field (such as a URL) that is also unique among all records. If you're using the SQLite database, the _ID field should be the following type:
確保包括了一個名字爲」_id」的整型列,用於記錄的IDs.不管你是否捅有了其餘能夠惟一標識全部記錄的域,你也應捅有這個域。若是你使用SQLite數據庫,_ID域應是這樣的類型。
INTEGER PRIMARY KEY AUTOINCREMENT [整型,主健,自動增長]
The AUTOINCREMENT descriptor is optional. But without it, SQLite increments an ID counter field to the next number above the largest existing number in the column. If you delete the last row, the next row added will have the same ID as the deleted row. AUTOINCREMENT avoids this by having SQLite increment to the next largest value whether deleted or not.
AUTOINCREMENT的描述是可選的。可是若是不帶上該描述,SQLite將在該列存在的最大數值之上,增長一個ID計數。若是我刪除最後一行,下一個增長的行將與刪除的行ID是相同的。AUTOINCREMENT是爲避免這種狀況,不管是否刪除,都在下一個最大值上增長.
·         Carefully document the data type of each column. Clients need this information to read the data.每列數據類型的詳細文件,客戶端須要這些信息讀取數據
·         If you are handling a new data type, you must define a new MIME type to return in your implementation of ContentProvider.getType(). The type depends in part on whether or not the content: URI submitted to getType() limits the request to a specific record. There's one form of the MIME type for a single record and another for multiple records. Use the Uri methods to help determine what is being requested. Here is the general format for each type:
·         若是你處理一新的數據類型 ,你必須在你的 ContentProvider.getType()實現中,返回定義的新MIME類型 。
o    For a single record:    vnd.android.cursor.item/vnd. yourcompanyname.contenttype
For example, a request for train record 122, like this URI,
content://com.example.transportationprovider/trains/122
might return this MIME type:
vnd.android.cursor.item/vnd.example.rail
o    For multiple records:    vnd.android.cursor.dir/vnd. yourcompanyname.contenttype
For example, a request for all train records, like the following URI,
content://com.example.transportationprovider/trains
might return this MIME type:
vnd.android.cursor.dir/vnd.example.rail
·         If you are exposing byte data that's too big to put in the table itself — such as a large bitmap file — the field that exposes the data to clients should actually contain a content: URI string. This is the field that gives clients access to the data file. The record should also have another field, named " _data" that lists the exact file path on the device for that file. This field is not intended to be read by the client, but by the ContentResolver. The client will call ContentResolver.openInputStream() on the user-facing field holding the URI for the item. The ContentResolver will request the " _data" field for that record, and because it has higher permissions than a client, it should be able to access that file directly and return a read wrapper for the file to the client.
若是你將解釋的數據太大,不能存在表中——好比一個大bitmap文件——解釋數據給客戶端的域應包括一個 content: URI字串,這個域給客戶訪問數據文件。這個記錄也應有另外一個域,叫作」_data」,它列出了數據文件在設備上的確切路徑。這個域不是給客戶端讀取的,而是爲內容解釋者提供的。客戶端將調用持有該項URI的面向用戶的 ContentResolver.openInputStream()方法。ContentResolver將請求「_data」域。因爲它的權限比客戶端高,它應能直接訪問文件,而且返回一個文件的包裹給客戶端.
For an example of a private content provider implementation, see the NodePadProvider class in the Notepad sample application that ships with the SDK.
關於內容提供者實現的例子,請看NodePadProvider類,在NotePand例子應用中,SDK帶有。
Declaring the content provider聲明內容提供者
To let the Android system know about the content provider you've developed, declare it with a <provider> element in the application's AndroidManifest.xml file. Content providers that are not declared in the manifest are not visible to the Android system
爲了讓系統知道你開發的內容提供者,在應用的AndroidManifest.xml文件中用 <provider>元素聲明它。沒有在manifest文件中聲明的內容提供者,對Android系統不可見。
The name attribute is the fully qualified name of the ContentProvider subclass. The authorities attribute is the authority part of the content: URI that identifies the provider. For example if the ContentProvider subclass is AutoInfoProvider, the <provider> element might look like this:
name屬性是內容提供者子類的全限定名。 Authorities屬性,是指定內容提供者的content:URI的部分認證。好比,如查ContentProvider子類是AutoInfoProvider,它的<provider>元素,多是這樣的:
<provider android:name="com.example.autos.AutoInfoProvider"
          android:authorities="com.example.autos.autoinfoprovider" 
          . . . />
</provider>
Note that the authorities attribute omits the path part of a content: URI. For example, if AutoInfoProvider controlled subtables for different types of autos or different manufacturers,
注意, authorities屬性省略了content: URI的部分路徑。好比,AutoInfoProvider控制不一樣汽車類型和不一樣廠商的子表
content://com.example.autos.autoinfoprovider/honda content://com.example.autos.autoinfoprovider/gm/compact content://com.example.autos.autoinfoprovider/gm/suv
those paths would not be declared in the manifest. The authority is what identifies the provider, not the path; your provider can interpret the path part of the URI in any way you choose.
這些路麼不該用manifest中聲明。該認證是標識內容提供者,不是路徑。你的內容提供者能夠以你選擇的任意方式翻譯URI的部分路徑
Other <provider> attributes can set permissions to read and write data, provide for an icon and text that can be displayed to users, enable and disable the provider, and so on. Set the multiprocess attribute to " true" if data does not need to be synchronized between multiple running versions of the content provider. This permits an instance of the provider to be created in each client process, eliminating the need to perform IPC.
其餘 <provider>屬性,能夠設置讀取和寫入數據的權限,給用戶提供一個圖標及文本用來顯示,容許及禁止內容提供者等。若是數據不須要在多個運行的內容提供者之間同步,將multiprocess屬性設爲true.它容許在每一個客戶端進程中建立一個內容提供者的實例,消除了執行IPC的須要.
Content URI Summary內容URI小結
Here is a recap of the important parts of a content URI: 下面是內容URI的重要概述
A. Standard prefix indicating that the data is controlled by a content provider. It's never modified. 一個內容前綴,指定由內容提供者控制的數據,它永不會修改
B. The authority part of the URI; it identifies the content provider. For third-party applications, this should be a fully-qualified class name (reduced to lowercase) to ensure uniqueness. The authority is declared in the <provider> element's authorities attribute:
   URI 的認證部分,標識內容提供者,對於第三方應用,這應該是一個全類限定名(減致全小寫)以確保惟一性。認證聲明在 <provider>元素的 authorities屬性中。
C. <provider android:name=".TransportationProvider"
D.           android:authorities="com.example.transportationprovider"
          . . . >
E. The path that the content provider uses to determine what kind of data is being requested. This can be zero or more segments long. If the content provider exposes only one type of data (only trains, for example), it can be absent. If the provider exposes several types, including subtypes, it can be several segments long — for example, " land/bus", " land/train", " sea/ship", and " sea/submarine" to give four possibilities.
路徑是內容提供者用於肯定那種數據類型被請求的。這個能夠是0,或者更長的段值。若是內容提供者只解釋一種數據類型(好比只有trains),它能夠缺乏。若是內容提供者解釋多種類型。包括子類型,它能夠是多個段長。好比," land/bus", " land/train", " sea/ship", and " sea/submarine"提供了4種可能的值。
F. The ID of the specific record being requested, if any. This is the _ID value of the requested record. If the request is not limited to a single record, this segment and the trailing slash are omitted:
若是有的話,ID指定請求的記錄,這就是請求記錄的_ID值。若是請求沒有限定單個記錄,這個段和後綴斜線能夠省略
content://com.example.transportationprovider/trains
 
Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.
Android 4.0 r1 - 15 Dec 2011 23:11
相關文章
相關標籤/搜索