본문 바로가기
깡샘 코틀린

16-1 콘텐츠 프로바이더 이해하기

by 농농씨 2023. 7. 8.

액티비티, 브로드캐스트 리시버, 서비스에 이어 마지막 컴포넌트인 콘텐츠 프로바이더 컴포넌트를 살펴보자. 콘텐츠 프로바이더는 앱의 데이터를 다른 앱과 공유할 때 사용한다. 안드로이드 앱은 구글이 제공하는 기본 앱과 연동하는 일이 많으므로 콘텐츠 프로바이더를 잘 다룰 수 있어야 한다. 

 

콘텐츠 프로바이더앱끼리 데이터를 연동하는 컴포넌트이다. 예를 들어 앱을 개발하면서 다른 앱의 데이터를 사용할 때 콘텐츠 프로바이더를 이용한다. 이때 데이터는 대상 앱의 데이터베이스나 파일 또는 앱에 할당된 메모리에 있다. 콘텐츠 프로바이더를 이용하면 이런 저장소에 있는 데이터를 가져오거나 수정할 수 있다.

 

앱의 데이터는 그 앱의 구성 요소에서 이용할 때는 문제가 없지만 외부 앱에서는 기본적으로 접근하지 못한다. 외부 앱에서 마음대로 접근하면 보안 문제가 발생하기 때문이다. 그렇지만 앱을 만들다 보면 공유해야 하는 데이터도 있기 마련이다. 예를 들어 휴대폰에 저장된 주소록은 주소록 앱의 데이터이고, 카메라로 촬영한 사진은 갤러리 앱에 저장돼 있지만 모두 다른 앱에서 이용할 수 있다.

 

어떤 앱의 데이터를 다른 앱에서 이용할 수 있게 하려면 콘텐츠 프로바이더를 이용해야 한다. 예를 들어 내가 만든 앱의 데이터를 외부에 공개하려면 내 앱에 콘텐츠 프로바이더를 만들고 접근하는 방법을 제공해야 한다. 그러면 외부 앱에서 콘텐츠 프로바이더를 이용해 공개한 데이터에 접근할 수 있다.

 

 

콘텐츠 프로바이더 작성하기

콘텐츠 프로바이더는 ContentProvider 클래스를 상속받아서 다음과 같이 작성한다.

// 콘텐츠 프로바이더 작성
class MyContentProvider : ContentProvider() { // ContentProvider 클래스를 상속받아서 콘텐츠 프로바이더 만듦
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
    // 외부 앱에서 이런 재정의한 함수들을 호출하여 데이터 조작함
        return 0
    }
    
    override fun getType(uri: Uri): String? {
        return null
    }
    
    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        return null
    }
    
    override fun onCreate(): Boolean { 
    // 콘텐츠 프로바이더의 생명주기 함수로서, 시스템이 콘텐츠 프로바이더 객체를 생성할 때 자동 호출됨
        return false
    }
    
    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectinoArgs: Array<String>?, sortOrder: String?
    ): Cursor? {
        return null
    }
    
    override fun update(
        uri: Uri, values: contentValues?, selection: String?,
        selectionArgs: Array<String>?
    ): Int {
        return 0
    }
}

ContentProvide를 상속받은 클래스에 onCreate(), getType(), query(), insert(), update(), delete() 함수를 재정의해서 작성한다. onCreate() 함수는 콘텐츠 프로바이더의 생명주기 함수이며 시스템이 콘텐츠 프로바이더 객체를 생성할 때 자동으로 호출된다. 그리고 외부 앱에서 query(), insert(), update(), delete() 함수 등을 호출해 데이터를 조작한다.

 

외부 앱에서 query() 함수 외에 insert(), update(), delete() 함수를 호출할 수 있다면 내 앱의 저장소에 데이터를 저장하거나 삭제할 수 있다는 의미인가요?

❗️query(), insert(), update(), delete()는 콘텐츠 프로바이더를 만들 때 클래스에 꼭 정의해 줘야 하는 추상 함수이며, 외부에서 이 함수를 호출해 데이터를 저장하거나 변경, 삭제하 수 있다. 그런데 외부 요청으로 이를 허용하지 않겠다면 함수 내부를 구현하지 않으면 된다. 즉, 외부에서 호출할 수 있도록 함수를 정의해 두되 아무 내용도 작성하지 않으면 된다.

 

콘텐츠 프로바이더도 안드로이드 컴포넌트이므로 매니페스트에 등록해야 한다. 그런데 콘텐츠 프로바이더는 다른 컴포넌트와 달리 name 속성 뿐만 아니라 authorities 속성도 반드시 선언해야 한다.

// 매니페스트에 콘텐츠 프로바이더 등록
<provider // <provider> 태그 이용함
    android:name=".MyContentProvider" // name 속성 등록함
    android:authorities="com.example.text_provider" // 다른 컴포넌트와 달리 authorities 속성도 등록해야함
    android:enabled="true"
    android:exported="true"></provider>

콘텐츠 프로바이더는 <provider> 태그로 등록하며 name 속성은 등록하고자 하는 클래스명이다. 그리고 authorities 속성외부에서 이 콘텐츠 프로바이더를 이용할 때 식별값으로 사용되는 문자열이다. 따라서 authorities 속성값은 개발자가 지정하는 고유한 값이어야 한다.

 

 

콘텐츠 프로바이더 이용하기

콘텐츠 프로바이더는 인텐트와 상관이 없다. 콘텐츠 프로바이더는 필요한 순간에 시스템에서 자동으로 생성해주므로 query(), insert(), update(), delete() 함수만 호출해 주면 된다.

 

외부 앱에서 콘텐츠 프로바이더를 사용하려면 먼저 매니페스트에 해당 앱에 관한 패키지 공개 설정을 해줘야 한다.

// 패키지 공개 설정
<queries>
    <!--  둘 중 하나만 선언하면 된다.  -->
    <!--  <provider android:authorities="com.example.test_provider" />  -->
    // authorities 속성 사용하여 공개 설정하거나
    <package android:name=:com.example.test_outter /> // name 속성 사용하여 공개 설정함
</queries>

콘텐츠 프로바이더를 사용하는 앱의 매니페스트에 (방법)1️⃣대상 앱의 패키지명을 <package> 태그로 명시한다. 또는 2️⃣사용하려는 콘텐츠 프로바이더의 authorities 속성을 <provider> 태그로 선언해줘도 된다.

그리고 시스템에 등록된 콘텐츠 프로바이더를 사용할 때는 ContentResolver 객체를 이용한다.

// 시스템의 콘텐츠 프로바이더 사용
contentResolver.query(
    Uri.parse("content://com.example.text_provider"),
    null, null, null, null)

contentResolver 속성으로 ContentResolver 객체를 얻은 후에 데이터를 조작하는 다음과 같은 함수를 호출하면 된다.

  • public final int delete(Uri url, String where, String[] selectionArgs)
  • public final Uri intsert(Uri url, ContentValues values)
  • public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
  • public final int update(Uri uri, ContentValues values, String where, String[] selectionArgs)

*query: 질문

이 함수들의 첫 번째 매개변수는 대상 콘텐츠 프로바이더를 식별하는 Uri 객체이다. Uri 객체의 URL 문자열은 (URL 구성요소)1️⃣프로토콜명과 2️⃣콘텐츠 프로바이더의 식별자로 등록된 authorities값이어야 한다. 호스트에 지정한 문자열로 식별되는 콘텐츠 프로바이더의 query()나 insert(), update(), delete() 함수를 호출한다.

URL 구성
프로토콜(scheme) 호스트(host)(식별자로 등록된 authorities 값)
content:// com.example.text_provider

 

콘텐츠 프로바이더를 이용할 때 URL 문자열에서 호스트 뒤에 다음처럼 경로(path)를 설정할 수도 있다. 경로는 선택사항이지만 이를 이용해 조건을 명시할 수 있다. 경로에는 단어나 숫자를 사용하는데 단어로 끝나면 그 단어에 해당하는 모든 데이터를 의미하고, 숫자로 끝나면 그 숫자로 식별되는 데이터를 의미하는 조건으로 주로 사용된다.

URL에 조건 설정
프로토콜(scheme) 호스트(host) 경로(path)
content:// com.example.text_provider/ user/1

 

예를 들어 query() 함수를 호출하면서 첫 번째 매개변수인 Uri 객체의 문자열이 user로 끝난다면 user 데이터를 모두 가져오겠다는 의미이며, user/1로 끝난다면 user 데이터에서 1번으로 식별되는 데이터를 가져오겠다는 의미이다.

물론 콘텐츠 프로바이더를 사용하는 곳에서 경로에 조건을 명시했더라도 실제 이용되는 콘텐츠 프로바이더가 이 경로를 활용하지 않는다면 의미는 없다.

update(), insert() 함수의 매개변수로 지정되는 ContentValuesMap 형태의 집합 객체이다. 즉, 키-값으로 여러 건의 데이터를 ContentValues에 지정하고 이 객체를 insert(), update() 함수의 매개변수로 넘겨서 데이터를 저장하거나 수정한다. 그리고 query() 함수의 반환 타입인 Cursor도 가져올 데이터의 Map 객체이다.

'깡샘 코틀린' 카테고리의 다른 글

17-1 저장소에 데이터 보관하기  (0) 2023.07.09
16-2 안드로이드 기본 앱과 연동하기  (0) 2023.07.09
15-4 잡 스케줄러  (0) 2023.07.08
15-3 백그라운드 제약  (0) 2023.07.07
15-2 바인딩 서비스  (0) 2023.07.07