ContentProvider
内容提供者
ContentResolver
内容解释者
Cursor
指示器(指针)
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.provider
包中看到.你可以内容提供者所包含的数据(但是,对于某些数据,你需要取得相应的数据读取权限)
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
子类),或者把数据加入到已存在的内空提供者— (如果有一个)控制数据的同样的类型并你有权限写入它.(不好翻译)
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();
_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
|
_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.
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
对象和查询结果的讨论)
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.内容提供者的所有的URIs都以字串"
content://
"开始。内容:cheme identifies the data as being controlled by a content provider.
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:
CONTENT_URI
常量.比如,匹配某人电话的表格的URI,匹配某人所捅有的图片的URI(它们都由内通信录内容提供者所控制)
android.provider.Contacts.Phones.CONTENT_URI
android.provider.Contacts.Photos.CONTENT_URI
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.
ContentResolver
方法,都把它当成第一个参数。它指定了内容解释者与那个内容提供者对话,内容提供者定位到那个表格。
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对象。
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
常量.
_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:
content://. . . ./23
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);
query()
and
managedQuery()
methods delimit the query in more detail. They are:
query()
和
managedQuery()
方法的,其他参数,更详细的限定查询内容:
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.
android.provider.Contacts.Phones
定义了上电话面图表中的列名的常量
—ID, NUMBER, NUMBER_KEY, NAME,
等等。
WHERE
clause (excluding the
WHERE
itself). A
null
value returns all rows (unless the URI limits the query to a single record).
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.
ORDER BY
它自己),一个空值返回表格中记录的默认顺序,可能是无序的。
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");
_COUNT
field of each record.
_COUNT
域的,记录值。
_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
实现了这些接口,这也是为什么上面例子代码中只使用一个类名就可以引用它们的原因。
_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.
_COUNT
列,它的值对所有的行都是一样的。
_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
|
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 内容解释对象。
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.
getString()
,
getInt()
, 和
getFloat().(
然而,大多数类型,如果你调用读字串方法,Cursor
对象将给一个该数据所表示的字串值)
,Cursor
对象可让你从列索引读取列名,或者从列名读取列索引
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 imagePath;
do {
// Get the field values
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);
// Do something with the values.
...
} while (cur.moveToNext());
}
}
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.
Cursor.getBlob()
读取。它返回一个字节数组。
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.
ContentResolver.openInputStream()
方法,获取一个输入流
InputStream
对象,来读取数据。
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 内容解释方法将失败。
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:
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);
CONTENT_DIRECTORY
constant. The following code continues the previous example by adding a phone number and e-mail address for the record just created:
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, "[email protected]");
values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
getContentResolver().insert(emailUri, values);
ContentValues.put()
that takes a byte array. That would work for a small icon-like image 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()
方法,(这将导致内容提供者将数据存在一个文件中,并且在记录的隐藏域记录文件的路径)
MediaStore
content provider, the main provider that dispenses image, 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 image 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, "image/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 image", e);
}
ContentResolver.update()
method with the columns and values to change. 经批处理一组记录(比如,将”NY”改成”New York”到所有的域),调用
ContentResolver.update()
方法,带上列及要改变的值。
ContentResolver.delete()
with the URI of a specific row. 删除一行,用
ContentResolver.delete()
方法,带上一个包括指定行的URI
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簇,否则,你可能删除的记录,比你想要删除的记录多)
SQLiteOpenHelper
class to help you create a database and
SQLiteDatabase
to manage it. 设置存储数据的一个系统,大多数内容提供者使用Android的文件存储数据, 或者SQLite数据库系统.但是你可以以你想要的任何方法存储数据。Android提供了一个
SQLiteOpenHelper
类,帮助你创建一个数据库,并且用
SQLiteDatabase
管理它.
ContentProvider
class to provide access to the data.继
ContentProvider
承类,来提供数据访问。
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:
query()
insert()
update()
delete()
getType()
onCreate()
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
—用于非数据库存储的数据。
ContentResolver.notifyChange()
to notify listeners when there are modifications to the data. 出于好意,你可能也想调用
ContentResolver.notifyChange()
方法,通知监听器数据什么时候被改变了。
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");
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
content:
URIs, see the Content URI Summary at the end of this document. 想要概览content:URIs,请看本文档后面的 Content URI Summary.
public static
String constants that clients can use to specify the columns in queries and other instructions.
_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:
INTEGER PRIMARY KEY AUTOINCREMENT [整型,主健,自动增加]
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是为避免这种情况,无论是否删除,都在下一个最大值上增加.
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类型 。
vnd.android.cursor.item/vnd.
yourcompanyname.contenttype
content://com.example.transportationprovider/trains/122
vnd.android.cursor.item/vnd.example.rail
vnd.android.cursor.dir/vnd.
yourcompanyname.contenttype
content://com.example.transportationprovider/trains
vnd.android.cursor.dir/vnd.example.rail
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.
content:
URI字串,这个域给客户访问数据文件。这个记录也应有另一个域,叫做”_data”,它列出了数据文件在设备上的确切路径。这个域不是给客户端读取的,而是为内容解释者提供的。客户端将调用持有该项URI的面向用户的
ContentResolver.openInputStream()
方法。ContentResolver将请求“_data”域。由于它的权限比客户端高,它应能直接访问文件,并且返回一个文件的包裹给客户端.
<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
<provider>
元素声明它。没有在manifest文件中声明的内容提供者,对Android系统不可见。
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:
Authorities属性,是指定内容提供者的content:URI的部分认证。比如,如查ContentProvider子类是AutoInfoProvider,它的<provider>元素,可能是这样的:
<provider android:name="com.example.autos.AutoInfoProvider"
android:authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>
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
<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的需要.
<provider>
element's
authorities
attribute:
<provider>
元素的
authorities
属性中。
C. <provider android:name=".TransportationProvider"
D. android:authorities="com.example.transportationprovider"
. . . >
land/bus
", "
land/train
", "
sea/ship
", and "
sea/submarine
" to give four possibilities.
land/bus
", "
land/train
", "
sea/ship
", and "
sea/submarine
"提供了4种可能的值。
_ID
value of the requested record. If the request is not limited to a single record, this segment and the trailing slash are omitted:
content://com.example.transportationprovider/trains