Content Providers

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, images, 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.provider 패키지에서 그것들 중의 몇 개의 목록을 볼 수 있다. 여러분은 그것들이 보유하고 있는 데이터를 위해 이러한 프로바이더에게 쿼리query할 수 있다(비록, 어떤 것에 대해서는 여러분이 데이터를 읽기 위한 적절한 퍼미션을 획득해야 하지만).

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.

만약 자기 자신의 데이터를 퍼블릭public하게 만들고자 한다면, 여러분은 두 가지 옵션을 가진다: 자기 자신의 컨텐트 프로바이더(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.

컨텐트 프로바이더라는 덮개cover 아래에 있는 데이터를 실제로 저장하는 방법은 컨텐트 프로바이더를 설계한 사람에게 달려있다. 하지만 모든 컨텐트 프로바이더는 데이터 추가, 수정, 삭제와 같은 프로바이더를 쿼리하고 그 결과를 리턴받는 보편적인 인터페이스를 구현한다.

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.

하나의 쿼리가 개시될 때, 안드로이드 시스템은 쿼리의 대상이 되는 컨텐트 프로바이더를 식별하고, 그것이 로드되고 실행되도록 한다. 시스템은 모든 컨텐트 프로바이더ContentProvider 오브젝트를 인스턴스화 한다; 여러분은 스스로 그것을 할 필요는 결코 없다. 실제로, 여러분은 결코 컨텐트 프로바이더ContentProvider 오브젝트를 직접 다루지 않는다. 일반적으로는 각각의 컨텐트 프로바이더 타입 별로 하나의 인스턴스가 있을 뿐이다. 하지만 그것은 서로 다른 애플리케이션과 프로세스에 있는 여러 개의 컨텐트 리졸버ContentResolver와 커뮤니케이션할 수 있다. 프로세스들 간의 상호작용은 컨텐트 리졸버ContentResolver와 컨텐트 프로바이더ContentProvider 클래스에 의해 제어된다.

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.

모든 레코드는 하나의 숫자numeric _ID 필드를 포함하며, 이것은 테이블 내에서 그 레코드를 고유하게 구분한다. ID들은 관련된 테이블 내의 레코드들을 매칭하기 위해 사용될 수 있다. 예를 들어 ID들은 하나의 테이블 내에서 특정인의 전화번호를 찾아서 다른 테이블에서 그 사람의 사진을 찾기 위해 사용될 수 있다.

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 오브젝트를 리턴한다. 그것은 각각의 데이터 타입을 읽기 위한 특별한 메쏘드를 가진다. 따라서 특정 필드를 읽기 위해서 여러분은 그 필드가 어떤 타입의 데이터 보유하고 있는 지를 알아야 한다(쿼리의 결과와 커서 오브젝트에 대한 더 많은 것들은 나중에 설명된다).

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.

각각의 컨텐트 프로바이더는 그 데이터 집합을 고유하게 식별하는 하나의 퍼블릭public URI(Uri 오브젝트로 감싸여짐)를 제공한다. 여러 개의 데이터 집합(여러 개의 테이블)을 제어하는 컨텐트 프로바이더는 각각에 대한 별도의 URI를 제공한다. 프로바이더를 위한 모든 URI는 “content://” 라는 문자열로 시작된다. content: 스키마scheme는 그 데이터가 컨텐트 프로바이더에 의해 제어되는 것으로 간주한다.

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를 상수로 정의하는 것이 좋다. 안드로이드는 안드로이드 플랫폼에 있는 모든 프로바이더에 대해 CONTENT_URI 상수를 정의하고 있다. 예를 들어 (컨택 프로바이더에 의해 둘 다 제어되는) 전화번호를 사람에 매칭시키는 테이블에 대한 URI와 사람에 대한 사진을 보유하고 있는 테이블에 대한 URI는 다음과 같다.

android.provider.Contacts.Phones.CONTENT_URI
android.provider.Contacts.Photos.CONTENT_URI

android.provider.Contacts.Phones.CONTENT_URI android.provider.Contacts.Photos.CONTENT_URI

Similarly, the URIs for the table of recent phone calls and the table of calendar entries are:

유사한 형태로, 최근 전화 통화 테이블과 캘린더 테이블에 대한 URI는 다음과 같다.

android.provider.CallLog.Calls.CONTENT_URI
android.provider.Calendar.CONTENT_URI

android.provider.CallLog.Calls.CONTENT_URI android.provider.Calendar.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 메쏘드는 그것의 첫 번째 매개변수로 URI를 갖는다. 그것은 컨텐트 리졸버ContentResolver가 어떤 프로바이더와 말해야 하는 지, 그리고 프로바이더의 어떤 테이블이 대상이 되어야 하는가를 구분한다.

Querying a Content Provider

You need three pieces of information to query a content provider:

여러분이 컨텐트 프로바이더에게 쿼리하기 위해서는 세 가지 정보가 필요하다.

  • The URI that identifies the provider
  • The names of the data fields you want to receive
  • The data types for those fields
  • 프로바이더를 식별하는 URI
  • 여러분이 받고자 하는 데이터 필드들의 이름들
  • 그 필드들의 데이터 타입들

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() 메쏘드를 사용할 수 있다. 두 메쏘드 모두는 동일한 매개변수 집합을 가지며, 둘 다 커서 오브젝트를 리턴한다. 하지만 managedQuery()는 액티비티로 하여금 커서Cursor의 생명주기를 관리할 수 있게 한다. 매니지드 커서managed Cursor는 액티비티가 멈출 때 스스로를 제거unloading하고, 액티비티가 다시 시작될 때 스스로를 재쿼리하는 것과 같이 모든 것을 세심하게 관리한다. 여러분은 Activity.startManagingCursor()를 호출함으로써, 관리되지 않는 커서unmanaged 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 상수는 특정 컨텐트 프로바이더와 데이터 집합을 식별한다(앞쪽의 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 값을 추가할 수 있다. 다시 말하면 URI path(경로) 영역의 마지막 위치에 ID와 일치하는 문자열을 넣으면 된다. 예를 들어 ID가 23인 경우에 URI는 다음과 같게 된다.

content://. . . ./23

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:

이곳에는 몇 개의 헬퍼helper 메쏘드가 있는데, 특별히 ContentUris.with AppendedId()와 Uri.withAppendedPath()는 URI에 ID를 추가하는 것을 용이하게 한다. 두 메쏘드 모두는 추가된 ID를 보유한 Uri 오브젝트를 리턴하는 정적static 메쏘드들이다. 그래서 예를 들어 만약 여러분이 사람들의 전화번호 데이터베이스에서 레코드 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 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 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 &mdash _ID, NUMBER, NUMBER_KEY, NAME, and so on.
  • 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).

  • 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.

  • 리턴받아야 하는 데이터 컬럼의 이름들. 널null 값은 모든 모든 컬럼을 리턴한다. 그렇지 않다면, 그 이름으로 리스트된 컬럼만 리턴된다. 그 플랫폼에 속하는 모든 컨텐트 프로바이더는 그들의 컬럼에 대한 상수를 정의한다. 예를 들어 android.provider.Contacts.Phones 클래스는 앞에서 설명된 phone 테이블에 있는 _ID, NUMBER, NUMBER_KEY, NAME, 그리고 기타 등등의 컬럼 이름에 대한 상수를 정의한다.
  • SQL WHERE 절(WHERE 자신은 제외함)로 형성되는 것으로, 리턴할 행들을 기술하는 필터. 널(null) 값은 모든 행들을 리턴한다(단, URI가 하나의 레코드로 쿼리를 제한하지 않는 한).

  • 선택할 것에 대한 아규먼트들

  • SQL ORDER BY 절(ORDER BY 자신은 제외함)로 형성되는 것으로, 리턴될 행에 대한 정렬 순서. 널(null) 값은 테이블에 대한 디폴트 순서, 어쩌면 정렬되지 않을 수도 있는 형태로 레코드들을 리턴한다.

Let's look at an example query to retrieve a list of contact names and their primary phone numbers:

컨택contact의 이름들과 그들의 기본적인 전화번호에 대한 리스트를 가져오기 위한 하나의 쿼리 예제를 살펴보자.

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.

이 쿼리는 컨택Contacts 컨텐트 프로바이더의 People 테이블에서 데이터를 가져온다. 그것은 각 컨택contact에 대한 이름, 주요 전화 번호, 그리고 고유한 레코드 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.

컬럼의 이름에 대한 상수는 다양한 인터페이스로 정의된다 - BaseColumns에 있는 _ID와 _COUNT, PeopleColumns에 있는 NAME, 그리고 PhoneColumns에 있는 NUMBER가 그것이다. 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.

가져온 데이터는 커서 오브젝트에 의해 보여지게 된다. 커서 오브젝트는 그 결과 집합set을 뒤 또는 앞으로 반복하기iterate 위해 사용될 수 있다. 여러분은 단지 데이터를 읽기 위해서만 이 커서 오브젝트를 사용할 수 있다. 데이터를 추가하고, 수정하고, 또는 삭제하기 위해서, 여러분은 컨텐트 리졸버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.

쿼리에 의해 리턴되는 커서 오브젝트는 결과의 레코드 집합set에 대한 접근을 제공한다. 만약 여러분이 ID로 특정 레코드를 쿼리했다면, 이 집합은 오직 하나의 값만을 포함할 것이다. 그렇지 않다면, 그것은 다수의 값들을 포함할 수 있다(만약 아무것도 일치하지 않는다면, 그것은 또한 빈(empty) 것이 될 수 있다). 여러분은 레코드에 있는 특정 필드에서 데이터를 읽을 수 있다. 그러나 여러분은 필드의 데이터 타입을 알아야만 한다. 왜냐하면 커서 오브젝트는 각각의 데이터 타입을 읽기 위한 별도의 메쏘드를 가지고 있기 때문이다 ? getString(), getInt(), 그리고 getFloat() 같은 것이 그것이다(하지만 대부분의 타입에 대해, 여러분이 스트링을 읽기 위한 메쏘드를 호출한다면, 커서 오브젝트는 여러분에게 데이터에 대한 스트링 표현을 제공할 것이다). 커서는 컬럼의 인덱스로부터 컬럼 이름을, 또는 컬럼 이름으로부터 인덱스 숫자를 여러분이 요청하는 것을 가능하게 한다.

The following snippet demonstrates reading names and phone numbers from the query illustrated earlier:

다음에 나오는 단편snippet은 앞서 설명된 쿼리에서 이름과 전화번호를 읽는 것을 보여준다:

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());

    }
}

If a query can return binary data, such as an image 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.

만약 쿼리가 이미지나 사운드 같은 바이너리 데이터를 리턴할 수 있다면, 그 데이터가 테이블 안에 직접 입력되어 있을 수도 있고, 또는 그 데이터에 대한 테이블 엔트리는 여러분이 데이터를 얻을 수 있는 content: 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.

만일 테이블 엔트리가 content: URI라면, 여러분은 직접 파일을 오픈하고 읽는 것을 결코 시도해서는 안된다(첫 째는 퍼미션 문제가 이것을 실패하게 만들 수 있다). 대신에, 여러분은 데이터를 읽기 위해 사용할 수 있는 InputStream 오브젝트를 얻기 위해 ContentResolver.openInputStream()을 호출해야 한다.

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:

새로운 레코드를 컨텐트 프로바이더에 추가하기 위해, 먼저 ContentValues 오브젝트에 키-값 쌍key-value pair의 맵map을 구성하라. 그 오브젝트의 각각의 키는 컨텐트 프로바이더에 있는 컬럼의 이름과 매칭되며, 그 값은 그 컬럼 내의 신규 레코드에서 요구되어지는 값이다. 그런 다음에 ContentResolver.insert()를 호출하고, 그것에게 프로바이더의 URI와 ContentValues 맵을 전달하라. 이 메쏘드는 새로운 레코드에 대한 전체 URI를 리턴한다 ? 즉, 새로운 레코드를 위해 추가된 ID를 가지는 프로바이더의 URI이다. 나중에 여러분은 쿼리를 위해 이 URI를 사용할 수 있고, 새로운 레코드에 대한 커서를 얻을 수 있고, 더 나아가 레코드를 수정하기 위해 사용할 수 있다. 여기에 예제가 있다:

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 또는 전자메일 같은 ? 정보를 추가하는 것이 될 것이다.

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:

컨택Contacts 데이터베이스의 하나의 레코드에 추가하는 최고의 방법은 그 레코드에 대한 URI에 새로운 데이터가 들어갈 테이블의 이름을 덧붙이는append 것이다. 그런 다음에 새로운 데이터 값을 추가하기 위해 수정된 URI를 사용하는 것이다. 각각의 컨택Contacts 테이블은 이러한 목적을 위해 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 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()을 호출함으로써, 테이블 안에 적은 양의 바이너리 데이터를 넣을 수 있다. 예를 들어 그것은 작은 아이콘 같은 이미지나 짧은 오디오 클립을 위한 작업이 될 것이다. 그러나 만약 여러분이 사진이나 완전한 노래같은 것들을 추가하기 위한 큰 양의 바이너리 데이터를 가진다면, 그 데이터에 대한 content:: URI를 테이블에 넣고, 그리고 그 파일의 URI를 가지고 ContentResolver.openOutputStream()을 호출하라(그것은 컨텐트 프로바이더가 파일로 데이터를 저장하고, 숨겨진 레코드 필드에 그 파일 경로를 기록하게 할 것이다).

In this regard, the 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:

이런 점에 있어서 이미지, 오디오, 그리고 비디오 데이터를 배분하는 메인main 프로바이더인 미디어 스토어MediaStore 컨텐트 프로바이더는 특별한 규정convention을 채택하고 있다. (주어진 사진의 제목 또는 사진이 찍힌 날짜 같은) 바이너리 데이터에 관한 메타 정보를 얻기 위해 query() 또는 managedQuery()에서 사용된 동일한 URI가 데이터 그 자체를 얻기 위한 openInputStream()에서 사용된다. 비슷하게, 메타 정보를 미디어 스토어MediaStore 레코드에 넣기 위해 insert()에서 사용된 동일한 URI가 그곳에 바이너리 데이터를 넣기 위한 openOutputStream()에서 사용된다. 다음에 오는 코드 단편snippet은 이 규정을 설명한다. (역주 : 위의 내용에서 query() 또는 insert()에서 사용된 동일한 URI가 아니라, 그 결과 URI가 openInputStream()과 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);
}

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.

하나의 레코드를 삭제하기 위해서는, 특정 행에 대한 URI를 가지는 ContentResolver.delete()를 호출하라..

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!).

다수의 행을 삭제하기 위해서는, 삭제하고자 하는 레코드 타입의 URI(예를 들어 android.provider.Contacts.People.CONTENT_URI)와 삭제할 행을 정의하는 SQL WHERE 절(clause)을 가지고 ContentResolver.delete()를 호출하라(주의: 만약 여러분이 일반적 타입을 삭제하거나 또는 여러분이 의도했던 것보다 더 많은 레코드를 삭제할 위험이 있다면, 유효한 WHERE 절(clause)을 포함했는가를 확인하라).

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.
  • Extend the ContentProvider class to provide access to the data.

  • Declare the content provider in the manifest file for your application (AndroidManifest.xml).

  • 데이터를 저장하기 위한 시스템을 구성하라. 대부분의 컨텐트 프로바이더는 안드로이드의 파일 저장 메쏘드 또는 SQLite 데이터베이스를 사용하여 자신의 데이터를 저장한다. 그러나 여러분은 자신이 원하는 임의의 방법으로 여러분의 데이터를 저장할 수 있다. 안드로이드는 여러분이 데이터베이스를 생성하는 것을 돕기 위해, SQLiteOpenHelper 클래스와 그것을 관리하기 위한 SQLiteDatabase를 제공한다.
  • 데이터에 대한 접근을 제공하기 위해 컨텐트 프로바이더 클래스를 확장하라.

  • 여러분의 애플리케이션에 대한 매니페스트 파일(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:

여러분은 컨텐트 리졸버ContentResolver와 커서Cursor 오브젝트에 의해 기대되는 규약convension을 사용하는 다른 것들에게, 여러분의 데이터를 보여주기 위해 컨텐트 프로바이더ContentProvider 서브클래스를 정의한다. 주로 이것은 컨텐트 프로바이더ContentProvider 클래스에 선언된 여섯 개의 추상 메쏘드를 구현하는 것을 의미한다.

query()
insert()
update()
delete()
getType()
onCreate()

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() 메쏘드는 요청받은 데이터를 반복할iterate 수 있는 커서Cursor 오브젝트를 리턴해야 한다. 커서 자체는 하나의 인터페이스이다. 하지만 안드로이드는 여러분이 사용할 수 있는 미리 만들어진 몇 개의 커서 오브젝트를 제공한다. 예를 들어 SQLiteCursor는 SQLite 데이터베이스에 저장된 데이터를 반복할iterate 수 있다. 여러분은 임의의 SQLiteDatabase 클래스의 query() 메쏘드들을 호출함으로써 커서 오브젝트를 얻는다. 거기에는 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.

이러한 컨텐트 프로바이더 메쏘드들은 다른 프로세스와 쓰레드에 있는 다양한 컨텐트 리졸버ContentResolver 오브젝트에서 호출될 수 있기 때문에, 그들은 쓰레드-세이프thread-safe 방식으로 구현되어야 한다.

As a courtesy, you might also want to call ContentResolver.notifyChange() to notify listeners when there are modifications to the data.

관례에 따라, 여러분은 또한 데이터에 대한 수정이 있을 때, 리스너listener에게 통지하기 위해 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:
    public static final Uri CONTENT_URI = 
                   Uri.parse("content://com.example.codelab.transporationprovider");

    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://com.example.codelab.transporationprovider/train
    content://com.example.codelab.transporationprovider/air/domestic
    content://com.example.codelab.transporationprovider/air/international

    For an overview of content: URIs, see the Content URI Summary at the end of this document.

  • 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.

    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:

    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.

  • 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:

    • 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

    • 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.

  • CONTENT_URI 라고 명명된 public static final Uri를 정의하라. 이것은 여러분의 컨텐트 프로바이더가 취급하는 전체 content: URI 를 나타내는 문자열이다. 여러분은 이 값에 대한 고유한 문자열을 정의해야 한다. 최선의 해법은 (소문자로 만들어진) 컨텐트 프로바이더의 전체 클래스 이름fully-qualified class name을 사용하는 것이다. 그러므로 예를 들어 TransportationProvider 클래스를 위한 URI는 다음과 같이 정의될 수 있다:
    public static final Uri CONTENT_URI = 
                   Uri.parse("content://com.example.codelab.transporationprovider");

    만약 프로바이더가 서브테이블들을 가진다면, 또한 각각의 서브테이블들에 대한 CONTENT_URI 상수들을 정의하라. 이러한 URI 들은 모두 동일한 authority(권위)를 가져야 하며(왜냐하면, 컨텐트 프로바이더를 식별해야 하기 때문에), 그것들의 경로path에 의해서만 구별되어야 한다. 예를 들어 다음과 같다.

    content://com.example.codelab.transporationprovider/train content://com.example.codelab.transporationprovider/air/domestic content://com.example.codelab.transporationprovider/air/international

    content: URI에 대한 개요에 대해서는, 이 장의 끝에 있는 컨텐트 URI 요약을 보라.

  • 컨텐트 프로바이더가 클라이언트에게 리턴할 컬럼 이름들을 정의하라. 만약 여러분이 데이터베이스를 사용하고 있다면, 이 컬럼 이름은 그들이 나타내는 SQL 데이터베이스 컬럼 이름과 전형적으로 동일하다. 또한 클라이언트가 쿼리와 다른 명령에서 컬럼들을 지정하기 위해 사용할 수 있는 public static String 상수를 정의하라.

    레코드의 ID에 대한 “_id”(상수 _ID를 가지는)라 이름 부쳐진 정수integer 컬럼을 포함하는 것을 확인하라. 여러분은 또한 (URL과 같은) 다른 필드를 가지는 지와 상관없이 모든 레코드에 고유한 이 필드를 가져야 한다. 만약 여러분이 SQLite 데이터베이스를 사용한다면, _ID 필드는 다음과 같은 타입이 되어야 한다.

    INTEGER PRIMARY KEY AUTOINCREMENT

    AUTOINCREMENT 기술자(descriptor)는 선택사항이다. 하지만 그것이 없다면, SQLite는 그 컬럼에 존재하는 가장 큰 숫자 위의 다음 숫자로 ID 카운터 필드를 증가시킨다. 만약에 여러분이 마지막 레코드를 삭제한다면, 다음에 추가된 행은 삭제된 행과 같은 ID를 가질 것이다. AUTOINCREMENT는 그 값이 삭제되었는지 여부와 상관없이 SQLite에 의해 다음으로 가장 큰 값으로 증가됨으로써 이것을 회피한다.

  • 신중하게 각각의 컬럼의 데이터 타입을 문서화하라. 클라이언트는 데이터를 읽기 위해 이 정보가 필요하다.

  • 만약 여러분이 새로운 데이터 타입을 취급하고 있다면, 여러분은 Content Provider.getType()을 구현하는 곳에서 새로운 MIME 타입을 리턴하도록 정의해야 한다. getType()에 제시된 content: URI가 특정 레코드에 대한 요청을 제한하던 안하던간에 그 타입은 부분적으로 content: URI에 의존한다. 그것에는 하나의 레코드에 해당되는 MIME 타입 형식 한 개와, 여러 개의 레코드에 해당되는 또 다른 MIME 타입 형식이 있다. 요구되는 것이 무엇인가를 결정하는 것을 돕기 위한 URI 메쏘드들을 사용하라. 여기에 각각의 타입에 대한 일반적인 포맷이 있다.

    • 하나의 레코드에 대해: vnd.android.cursor.item/vnd.yourcompanyname.contenttype

      예를 들어, 아래의 URI와 같이 train 레코드 122를 요청할 경우,

      content://com.example.transportationprovider/trains/122

      아래의 MIME 타입을 리턴할 수 있다.

      vnd.android.cursor.item/vnd.example.rail

    • 다수의 레코드에 대해: vnd.android.cursor.dir/vnd.yourcompanyname.contenttype

      예를 들어, 아래의 URI와 같이 모든 train 레코드를 요청할 경우

      content://com.example.transportationprovider/trains

      아래의 MIME 타입을 리턴할 수 있다.

      vnd.android.cursor.dir/vnd.example.rail

  • 만약 여러분이 - 큰 비트맵 파일 같은 - 테이블 자체에 넣기에는 너무 큰 바이트 데이터를 보여주고 있다면, 클라이언트에게 그 데이터를 보여주는 그 필드는 실제 content: URI 문자열을 포함해야 한다. 이것은 그 데이터 파일에 클라이언트가 접근하도록 주어지는 필드이다. 그 레코드는 또한 그 파일에 대한 디바이스 상의 정확한 파일 경로를 나타내는 “_data”라고 명명된 또 다른 필드가 있어야 한다. 이 필드는 클라이언트가 아니라, 컨텐트 리졸버ContentResolver에 의해 읽혀지도록 의도된 것이다. 클라이언트는 그 아이템을 위한 URI를 보유하는 사용자가 접하는 필드에 대해서 ContentResolver.openInputStream()를 호출할 것이다. 컨텐트 리졸버ContentResolver는 그 레코드에 대한 “_data” 필드를 요청할 것이다. 그리고 그것이 클라이언트 보다 더 높은 퍼미션을 가지고 있기 때문에, 그것은 그 파일에 직접적으로 접근할 수 있어야 하며, 그 클라이언트에게 파일에 대한 읽기 위한 용기wrapper를 리턴한다.

For an example of a private content provider implementation, see the NodePadProvider class in the Notepad sample application that ships with the SDK.

개인적인 컨텐트 프로바이더 구현 예제를 대해서는, SDK와 함께 배포되는 노트패드NotePad 샘플 애플리케이션에 있는 NodePadProvider 클래스를 보라.

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> 엘리먼트를 사용해서 그것을 정의하라. 매니페스트에 선언되지 않은 컨텐트 프로바이더는 안드로이드 시스템에게 보여지지 않는다.

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 애트리뷰트는 컨텐트 프로바이더ContentProvider 서브클래스의 전체 이름이다. authorities 애트리뷰트는 프로바이더를 식별하는 content: URI의 authority 영역이다. 예를 들어 만약 컨텐트 프로바이더ContentProvider 서브클래스가 AutoInfoProvider라면, <provider> 엘리먼트는 아래와 같이 보일 수 있다.

<provider name="com.example.autos.AutoInfoProvider"
          authorities="com.example.autos.autoinfoprovider" 
          . . . /&gt
</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의 path(경로) 영역을 생략한다는 것에 주의하라. 예를 들어 만약 AutoInfoProvider가 다른 타입의 자동차 또는 다른 제조업체에 대한 서브테이블을 제어한다면,

content://com.example.autos.autoinfoprovider/honda
content://com.example.autos.autoinfoprovider/gm/compact
content://com.example.autos.autoinfoprovider/gm/suv

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.

그러한 path는 매니페스트 안에서 선언되지 않을 것이다. path(경로)가 아니라, authority(권위)가 프로바이더를 식별하는 것이다. 여러분의 프로바이더는 여러분이 선택한 어떤 방식으로 URI의 path(경로) 영역을 해석할 수 있다.

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

Here is a recap of the important parts of a content URI:

여기에 content URI의 중요한 부분에 대한 요약이 있다.

Elements of a content URI

  1. Standard prefix indicating that the data is controlled by a content provider. It's never modified.
  2. 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:

    <provider name=".TransportationProvider"
              authorities="com.example.transportationprovider"
              . . .  >
  3. 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.

  4. 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:

    content://com.example.transportationprovider/trains

  1. 데이터가 컨텐트 프로바이더에 의해 제어된다는 것을 가리키는 표준 접두어. 그것은 결코 수정되지 않는다.
  2. URI의 authority(권위) 영역; 그것은 컨텐트 프로바이더를 식별한다. 제3자third-party 애플리케이션에 대해서, 이것은 유일성을 보장하기 위해 (소문자로 된) 전체 클래스 이름이 되어야 한다. authority는 <provider> 엘리먼트의 authorities 애트리뷰트에서 선언된다.

    <provider name=".TransportationProvider"
              authorities="com.example.transportationprovider"
              . . .  >
  3. path(경로)는 컨텐트 프로바이더가 요청되는 데이터의 종류를 결정하기 위해 사용된다. 이것은 없을 수도 있으며, 또한 길게 많이 세그먼트될 수 있다. 만약 컨텐트 프로바이더가 오직 하나의 데이터 타입(예를 들어 기차만)만을 보여준다면, 이것은 존재하지 않을 수 있다. 만약 프로바이더가 서브타입을 포함하여 여러 개의 타입을 보여준다면, 그것은 길게 몇 개로 세그먼트 될 수 있다. 예를 들어 네 개의 가능성을 주기 위해, “land/bus”, “land/train”, “sea/ship”, 그리고 “sea/submarine”가 될 수 있다.

  4. 만약 있다면, 요청되는 특정 레코드의 ID. 이것은 요청된 레코드의 _ID 값이다. 만약 요청이 하나의 레코드에 제한되지 않는다면, 이 부분과 마직막 슬래쉬(/)는 생략된다.

    content://com.example.transportationprovider/trains

↑ Go to top