본문 바로가기
Android/Android 기초

[Android] 안드로이드 4대 컴포넌트(4) - 콘텐트프로바이더(ContentProvider)

by 태크민 2023. 9. 3.

콘텐트 프로바이더 (ContentProvider)

콘텐트 프로바이더는 Android Application의 일부로써 앱간의 데이터를 공유할 수 있도 도와주는 컴포넌트이다.

콘텐트 프로바이더는 다음의 특징을 가진다.

  • 콘텐트 프로바이더는 외부 앱에게 관계형 데이터베이스의 테이블과 유사한 하나 또는 그 이상의 테이블로써 제공한다.
  • 하나의 행(Row)은 프로바이더가 제공하는 어떤 데이터 타입에 대한 객체를 나타내고, 그 행의 각 열(column)은 해당 객체가 가지고 있는 각 데이터를 나타낸다.
  • 콘텐트 프로바이더(다른 앱)와 클라이언트(나의 앱)은 보안적으로 안전하게 연결되어 내부적으로 프로세스간 통신(IPC)을 한다.

 


 

콘텐트 프로바이더 동작 매커니즘

앱은 ContentProvider에 데이터를 접근하기 위해 앱의 Context에서 ContentResolver 객체를 사용한다.

  • ContentResolver 객체는 ContentProvider를 구현(Implement)하는 클래스의 인스턴스와 통신할 수 있다. 해당 인스턴스는 클라이언트로 부터 데이터 요청을 수신하고 요청한 작업을 수행한 후 결과를 반환한다.
  • ContentResolver 객체의 메소드를 통해 데이터를 생성, 검색 업데이트, 삭제 등을 할 수 있다. 마치 데이터 베이스에서 query를 하듯 ContentResolver의 query() 메소드가 컨텐트 프로바이더로부터 데이터와 관련된 작업을 하게 된다.

메커니즘

다른 앱의 데이터를 가져오는 과정

일반적으로 ContentProvider에 접근할 때 CusorLoader를 통해 백그라운드 에서 비동기 쿼리를 호출하고 ContentResolver를 사용하여 ContentProvider를 가져온다. 이렇게 하면 쿼리를 실행하는 동안 UI가 멈추지 않고 계속할 수 있다.

 


Content URI

Content URI는 프로바이더의 데이터를 가리키는 URI다.

Content URI는 프로바이더 자체(보통 패키지명)를 나타는 authority와 테이블을 가리키는 path를 포함한다.

  1. ContentResolver 객체는 그 URI의 authority부분을 시스템이 알고 있는 프로바이더들의 authority들과 비교하여 맞는 것을 찾아서 그 프로바이더로 query 인자들을 보낸다.
  2. ContentProvider는 액세스할 테이블을 알기 위해 URI의 apth부분을 확인한다. 프로바이더는 보통 그 path 부분과 일치하는 이름의 테이블을 가지고 있다.
    content://com.example.provider/article/title 이런식으로 path/뒤에 구체적으로 어떠한 정보를 원하는지 명시하여 데이터를 받아올 수도 있다.

 


 

Content Provider로 부터 데이터 가져오기

예를 들어 사용자 사전 프로바이더에 있는 단어 및 장소 목록을 얻기 위해서 ContentResolver.query() 메소드를 호출하는데, 이것은 사용자 사전 프로바이더에 정의되어 있는 ContentProvider.query() 메소드를 호출한다.

1. 읽기 권한 요청

<uses-permission android:name="android.permission.READ_CONTACTS" />

 

2. 다른 앱의 ContentProvider에 쿼리 요청

ContentResolver resolver=getContentResolver(); 
Uri phoneUri= ContactsContract.CommonDataKinds.Phone.CONTENT_URI; 

String proj[]={ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER};

Cursor cursor= resolver.query(
phoneUri, //Uri: 프로바이더의 Table name과 대응(ex.. FROM table_name)
proj, //projection: select하여 가져올 데이터의 컬럼들과 대응
null, //selection: where 조건절(ex..WHERE col=value)
null, //selectionArgs
null); //sortOrder: 정렬기준(ex.. ORDER BY)

 

3. 결과 받아오기

위의 ContentResolver.query() 메소드는 쿼리의 Selection 조건에 부합하는 결과들에 대하여 쿼리의 projection에서 지정한 컬럼 값들을 담고 있는 Cursor 객체를 리턴해주며, Cursor객체를 통해 결과 값들에 엑세스 할 수 있다.

Cursor의 메소드들을 이용하여, 여러 행의 결과들에 대하여 순차적으로 각 행을 읽을 수 있고, 각 컬럼의 데이터 타입을 확인하여, 데이터를 얻을 수 있다.

..
..
//컨텐트 리졸버로 데이터 가져오기. 가져온형태 ->커서
Cursor cursor= resolver.query(phoneUri, proj,null,null,null);
//cursor에 데이터 존재여부
if(cursor !=null){
	while(cursor.moveToNext()){
		int index;
                index=cursor.getColumnIndex(proj[1]);
                String name=cursor.getString(index);
                
                index=cursor.getColumnIndex(proj[2]);
                String tel=cursor.getString(index);					
        }
}
cursor.close(); //닫지않으면 계속열려있음

 


 

데이터의 삽입, 갱신, 삭제

콘텐트 프로바이더로부터 데이터를 얻을 때와 마찬가지 방식으로 클라이언트(앱)이 다른앱의 데이터를 변경할 수도 있다.

 

ContentProvider에 대응되는 ContentResolver의 메소드를 호출하면 된다.

  • ContentResolver.insert(..)
  • ContentResolver.update(..)
  • ContentResolver.delete(..)
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "image_1024.JPG");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/*");

ContentResolver contentResolver = getContentResolver();
Uri item = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

insert() 함수는 Provider에 새로운 데이터를 추가하고 해당 데이터를 나타내는 URI를 리턴한다.