일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- androidStudio
- 암호학
- 코루틴
- boj
- AWS
- relay
- Python
- GitHub
- MiTweet
- MyVoca
- 프로그래머스
- 코드포스
- TEST
- Compose
- Codeforces
- livedata
- ProGuard
- Coroutine
- activity
- Coroutines
- 쿠링
- Rxjava
- architecture
- textfield
- 백준
- Kotlin
- android
- pandas
- Gradle
- Hilt
- Today
- Total
이동식 저장소
[Android Fundamentals] Content Provider - 1. Overview 본문
Concept
Content provider는 앱의 데이터를 캡슐화하고, ``ContentResolver`` 인터페이스를 통해 다른 앱에 제공함으로서 서로 다른 프로세스에서 데이터를 공유할 수 있는 표준 인터페이스의 역할을 한다. 앱 내부에서 사용할 수도 있지만, 데이터를 다른 앱에 제공하기 위해 사용되는 경우가 많다.
다른 앱에서는 provider client 객체를 사용하여 content provider에 접근한다. 즉 content provider와 provider client를 통해 일관된 데이터 인터페이스를 유지하는 동시에 데이터를 보호하고 프로세스 간 데이터 교환 작업까지 한번에 처리할 수 있다.
데이터를 다른 앱과 공유해야 할 때만 content provider를 사용하자. 예를 들어 연락처 정보는 많은 앱에서 참조하고 싶어할 수 있으므로 content provider에 저장되어야 한다. 공유할 필요가 없는 데이터는 ``Room``을 사용하여 db에 직접 저장하면 된다.
Content provider는 다른 앱에 노출하는 데이터 작업을 추상화함으로서 내부 구현이 바뀌어도 외부에 영향을 주지 않도록 할 수 있다.
이런 경우에는 커스텀 content provider를 정의해야 한다.
- 내 앱에 커스텀 검색 제안 로직을 구현할 때
- 내 앱의 위젯에 데이터를 넘겨줄 때
- 내 앱에서 다른 앱으로 복잡한 데이터를 복사/붙여넣기할 때
``ContentResolver``를 통해 요청이 들어오면, 시스템은 URI를 파싱하여 해당 URI를 처리할 수 있는 앱에 요청을 넘겨준다. Content provider는 시스템이 넘겨준 URI를 원하는 대로 해석할 수 있다. URI를 파싱할 때 ``UriMatcher``를 사용하면 좋다.
Content provider의 주요 메서드는 다음과 같다. 생명주기 메서드보단 데이터 관련 메서드가 많다.
- ``onCreate()``
- ``query(Uri, String, Bundle, CanellationSignal)``
- ``insert(Uri, ContentValues)``
- ``update(Uri, ContentValues, Bundle)``
- ``delete(Uri, Bundle)``
Overview
Content provider는 앱의 데이터 계층을 다른 API 및 컴포넌트와 연결하는 역할을 한다. Content provider가 사용되는 대표적인 경우는 다음과 같다.
- 다른 앱에 데이터를 공유할 때 (primary!)
- 위젯에 데이터를 보낼 때
- 검색 프레임워크에 커스텀 검색 제안 데이터를 보낼 때 (with ``SearchRecentSuggestionsProvider``)
- ``AbstractThreadSyncAdapter``를 implement하여 서버와 데이터를 동기화할 때
- UI에서 ``CursorLoader``를 사용하여 데이터를 로드할 때 (이건 진짜 old한 경우)
Content provider의 장점
Content provider를 사용하면 데이터 접근 권한을 다양하게 설정할 수 있다. 내 앱의 content provider만 데이터에 접근할 수 있게 제한할 수도 있고, 폭넓은 권한을 허용할 수도 있고, 읽기/쓰기 권한을 다르게 부여할 수도 있다.
안드로이드 프레임워크에는 음악, 영상, 이미지, 연락처 등의 정보를 관리하는 content provider가 내장되어 있다. 여기에서 목록을 확인할 수 있다. 내장된 provider는 (몇몇 제한이 걸려있긴 하지만) 모든 앱에서 접근할 수 있다.
위에서 언급한 ``CursorLoader`` 클래스는 비동기 쿼리를 수행하기 위해 content provider를 사용한다 .
Provider에 접근하기
Content provider의 데이터에 접근하고 싶다면, ``Context``에서 얻을 수 있는 ``ContentResolver`` 객체를 사용하여 클라이언트 역할로 접속해야 한다. ``ContentResolver``가 ``ContentProvider``에서 데이터를 얻어오는 구조이다.
Provider는 클라이언트로부터 데이터 요청을 받고, 요청을 처리하여 데이터를 반환한다. ``ContentProvider``와 ``ContentResolver`` 모두 기본적인 CRUD 함수를 제공한다. TMI이지만 두 클래스의 CRUD 함수 이름이 정확히 같다고 한다.
매우 old하긴 하지만, ``ContentProvider``에 접근하는 예시 중 하나는 ``Activity``나 ``Fragment``에서 ``CursorLoader``를 사용하여 데이터를 비동기적으로 받아오는 경우이다. Kotlin coroutines를 활용한 패턴의 원조 격이라고 볼 수 있을 듯.
Android에 내장된 provider 중에는 사용자가 키보드에 보관한 단어를 저장하는 User Dictionary Provider가 있다. 대략 이렇게 생겼다.
보면 알겠지만 관계형 DB와 매우 유사하다. 이 provider에 접근하는 코드는 다음과 같다.
// Queries the UserDictionary and returns results
cursor = contentResolver.query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
projection, // The columns to return for each row
selectionClause, // Selection criteria
selectionArgs.toTypedArray(), // Selection criteria
sortOrder // The sort order for the returned rows
)
문법이 거의 ``Words`` 테이블이라고 봐도 될 정도로 유사하다.
Content URI
Content URI는 provider에 저장된 데이터를 표현하는 URI이다. Provider의 이름(authority)과 데이터의 주소(path)로 구성된다. 안드로이드에 내장된 provider의 URI는 위 코드처럼 상수로 미리 정의되어 있지만, 커스텀 provider의 URI는 직접 만들어야 한다.
``ContentResolver``는 URI의 authority를 파싱하여 데이터를 가져올 provider를 결정한 후, provider에게 path 부분을 넘긴다. Path를 넘겨받은 ``ContentProvider``는 path를 파싱하여 쿼리 매개변수를 얻는다.
위에서 ``Words``에 접근할 때 사용한 URI의 실제 값은 이러하다.
content://user_dictionary/words
- ``content``: 이 URI가 컨텐츠를 나타내는 URI임을 명시한다.
- ``user_dictionary``는 provider의 이름(authority)이다.
- ``words``는 provider에 저장된 데이터 테이블의 이름이다.
이 URI는 매개변수가 없으므로 모든 데이터를 반환한다. 물론 매개변수를 더 붙일 수도 있다. ``_ID``가 4인 데이터를 찾는 URI는 다음과 같다.
val singleUri: Uri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4)
URI를 만들 때에는 ``Uri`` 또는 ``Uri.Builder`` 클래스를, URI에 데이터를 덧붙일 때에는 ``ContentUris`` 클래스를 사용하면 좋다.
참고자료
'Primary > Android' 카테고리의 다른 글
[Android Fundamentals] Activity - 3. Lifecycle (0) | 2024.07.14 |
---|---|
[Android Fundamentals] Activity - 2. Introduction to Activities (0) | 2024.07.13 |
[Android for Cars] Car App Library fundamentals (3) | 2024.07.07 |
[Android Fundamentals] Broadcast Receiver - 1. Overview (0) | 2024.07.07 |
[Android Fundamentals] Service - 1. Overview (0) | 2024.07.06 |