Content Provider는 Data를 저장하고 조회하며, 모든 Application에서 저장된 Data의 접근이 가능하도록 한다. Applicaiton간에 Data를 공유하는 유일한 방법이다.

안드로이드는 범용 data type(audio, image, video 등)에 대한 Content provider를 가지고 있으며 이것을 통해 Data를 조회할 수 있다.
Application의 Data를 public으로 하려면 ContentProvider의 subclass로 자신만의 Content Provider를 만들 수도 있고 기존의 provider에 Data를 추가할 수도 있다.

Content Provider Basics
  Content Provider가 어떻게 데이터를 저장하는지는 설계자의 몫이다. 하지만 모든 content provider는 provider를 조회하고 결과를 반환하는데 공통의 Interface를 구현해야 한다. (추가, 수정, 삭제 포함)
Client가 간접적으로 사용하는  Interface는 일반적으로 ContentResolver Object를 통한다. ContentResolver는 getContentResolver() method를 호출하여 얻을 수 있다.
ContentResolver cr = getContentResolver();

  Query가 시작되면 안드로이드 System은 Query의 Target인 Content Provider를 식별하고, 그것이 실행 중인지 확인한다.

1. The data model
  Content Provider는 database model의 단순한 table로 데이터를 진열하는데 각 row는 record이고 각 column은 특유의 타입과 의미를 가진 데이터이다.
모든 record는 table에서 record를 유일하게 식별하는 "_ID" field를 포함한다.
Query는 각 필드의 contents를 읽기 위해 record간, column간 이동할 수 있는 Cursor Object 를 반환한다. Cursor Object는 java의 ResultSet과 유사하게 각 데이터의 Type별로 method를 제공하므로, 각 필드의 데이터 Type을 알아야 한다.

2. URIs
  각 Content Provider는 data set을 유일하게 식별하는 public URI를 내놓으며, 다수의 data set을 제어하는 content provider는 각각에 대한 서로다른 URI를 내놓는다. 모든 URI는 "content://"로 시작하며, "content:"는 content provider에 의해 통제되는 data라는 것을 의미한다.
  만일 Content provider를 정의한다면, URI에 constant를 정의하고, client code를 단순화하며, 이 후 update를 명확히 하라. 안드로이드는 platform에 있는 모든 provider에 CONTENT_URI constant를 정의한다.
  URI constant는 content provider와의 모든 연동에 사용되며, 모든 ContentResolver method는 처음 argument로 URI를 받는다. 이를 통해 어떤 ContentResolver가 어떤 provider와 연동하는지 그리고 provider의 어떤 table이 target이 되는지 식별할 수 있다.

Querying a Content Provider
  Content Provider를 query하기 위해서는 provider를 식별할 수 있는 URI, 조회를 하는 데이터 필드명과 해당 필드의 데이터타입이 필요하다. 또한 특정 record를 조회하기위해서는 해당 record의 _ID가 필요하다.

1. Making a query
  Content Provider를 query하려면, ContentResolver.query()나 Activity.managedQuery() method를 사용한다. 두 method 모두 동일한 arguments를 사용하고 Cursor Object를 반환하지만, managedQuery() method는 Activity가 Cursor의 life cycle을 관리하도록 한다. managed Cursor는 Activit가 pause상태일 경우에는 unload 그리고 restart 상태일 경우 requery하는 것처럼 좀더 세밀하게 다룰 수 있다. 물론 unnmanaged cursor를 Acivity.startManagingCursor() method를 통해 managing을 시작할 수 있다.
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

  1) query(), managedQuery()의 처음 argument는 provider URI이다. 하나의 record만 조회한다면 URI에 _ID value를 첨부하면 가능하다.

content://. . . ./23

또는
ContentUris.withAppendedId(), Uri.withAppendedPath()를 사용하라

  2) projection은 반환되는 data column명이다. 만일 null 이면 모든 column을 반환한다. 
  3) selection은 query에 대한 조건절을 명시하면 된다. 이는 SQL의 WHERE절에 해당한다. null인 경우 모든 rows가 반환된다. 단 URI에 _ID가 있는 경우는 제외
  4) selectionArgs는 java의 PreparedStatement와 유사하며, selection에 ?가 포함되는 경우에 값을 치환한다.
  5) sortOrder는 row의 order를 설정한다. SQL의 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");


2. What a query returns
  Query는 0 또는 그 이상의 database record를 반환하는데 각 column명, order 및 data type은 각 content provider에 지정되어 있다. 위에서 언급한것 처럼 모든 provider는 _ID column을 가지고 있고 이는 각 record의 unique numeric ID이며, _COUNT column처럼 반환하는 resord의 갯수를 줄 수도 있다.

3. Reading retrieved data
  query의 결과로 반환된 Cursor object을 통해 data를 접근할 수 있다. Java의 ResultSet class와 마찬가지로 Cursor도 각 data의 type에 따라 method를 제공하므로 - getString(), getInt() 등 - 조회하려는 table의 data type을 미리 알아야 한다.
query의 결과가 binary data를 반환한다면, data가 table에 직접 입력이 되어 있거나, 해당 data를 위한 table entry가 data를 얻기 위해 사용되는 URI일 수 있다. 일반적으로 적은 양의 데이터는 table에 직접 입력할 수 있으며, 이 경우 Cursor.getBlob() method를 사용하여 byte array를 가져올 수 있다.
만일 table entry가 content:URI로 구성되어 있으면, 직접 열고 읽기을 할 수 없으며 ContentResolver.openInputStream()을 사용하여 InputStream object를 얻은 후 사용한다.

Modifying Data
  Data의 추가,수정,삭제는 ContentResolver method를 사요하여야 하며, Content Provider에 따라 제약이 있을 수 있다.

1. Adding records
  새로운 record를 추가하기 위해서는 ContentValues object에 key-value를 설정하여 ContentResolver.insert() method를 사용한다. key는 table의 column명이 된다.
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);


2. Adding new values
  record가 존재하고, 새로운 value를 입력하거나 기존 정보를 수정려는 경우, 기존 정보에 대한 URI를 조회하고 key-value를 설정하여 ContentResolver.insert() method를 사용한다. (이미 위에서 특정 record를 조회할 수 있는 방법 - URI-을 설명한바 있다.
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);


3. Batch updating records
  record group을 batch로 update하려면 ContentResolver.update()를 사용한다. Batch Update란 SQL의 WHERE 절 없이 전체 table의 record를 대상으로 update하는 것을 의미한다.

4. Deleting a record
  Single record는 ContentResolver.delete() method을 사용하여 delete한다.
Multiple records는 동일한 method를 사용하지만 WHERE 절을 사용하여야 한다.

Creating a Content Provider
  Content Provider를 생성하려면
1) data 저장을 위해 System을 설정한다. 대부분 content provider는 안드로이드의 file storage method나 SQLite database를 사용해 data를 저장하지만 원하는 방식으로 데이터를 저장할 수 있다.
2) Data에 접근성을 제공하기 위해 ContentProvider를 상속한다.
3) Application을 위해 content provider를 manifest file에 선언한다.

1. Extending the ContentProvider class
ContentProvider의 subclass를 정의하고 ContentProvider에 정의된 6개의 acstract method를 구현하여야 한다.
query(), insert(), update(), delete(), getType, onCreate() 가 있다.

  query() method는 Cursor object를 반환해야 한다. Cursor는 그 자체가 interface이지만 안드로이드는 사용자가 사용할 수 있는 몇 개의 ready-made Cursor를 제공한다. 예를 들면 SALiteCursor등이 있다.
  ContentProvider method는 다른 process나 thread에서, 다양한 ContentResolver object로부터 호출될 수 있으므로 thread-safe 방식으로 구현되어야 한다.

  1) "CONTENT_URI"라는 이름으로 pulic static final Uri 변수를 정의한다. 정의된 URI는 Content Provider에서 다루어지게 될 "content:URI" 이며, unique한 string으로 선언되어야 한다.
public static final Uri CONTENT_URI =
               Uri.parse("content://com.example.codelab.transporationprovider");


  2) Column name을 정의한다. record의 id를  위해 "_ID"가 포함되어야 한다.
  3) 각 column의 data type을 정의한다.
  4) 새로운 data type을 다루고자 한다면, 새로운 MIME type을 정의하여야 한다.
  5) 대용량의 byte data를 넣고자 한다면, file system에 저장하고 이에 대한 URI string을 저장하여 client가 접근하여 사용할 수 있도록 한다.

2. Declaring the content provider
  안드로이드 System에 사용자가 정의한 Content Provider를 인지시키기 위해서는 Application manifest file에 <provider> element를 사용하여 선언한다.
 
<provider name="com.example.autos.AutoInfoProvider"
          authorities="com.example.autos.autoinfoprovider"
          . . . />
</provider>


Content URI Summary
  아래 예제를 보면서 Content URI에 대해 요약 설명하도록 한다.

  A. Data가 Content Provider에 의해 제어되는 것을 지시하는 prefix
  B. URI의 Authority 부분으로 Content Provider를 식별한다.
  C.  Content Provider가 요청되고 있는 data의 종류를 결정하기 위해 사용되는 path.
  D. 특정 record의 ID.(생략 가능함. 생략하는 경우 전체 record)

Posted by 피의복수
BLOG main image
일에 필요한 자료 by 피의복수

카테고리

분류 전체보기 (40)
프로그램이야기 (38)
끄적끄적 (1)
취미 (0)
서비스이야기 (1)
빅데이터 (0)

최근에 올라온 글