중앙 레파지토리의 데이터를 관리한다. Android Application의 일부로 흔히 데이터 작업을 위한 UI 제공을 한다. 그러나 기본적으로 Content Provider는 Provider 클라이언트 오브젝트를 이용하여 Provider에 엑세스하는 다른 Application에서 사용하기 위한 것이다. Provider와 Provider 클라이언트가 결합하면 데이터에 하나의 일관적인 표준 인터페이스를 제공하여 이것이 프로세스간 통신과 보안 데이터 엑세스도 처리한다.
일반적으로 두 경우 중 하나에서 Content Provider를 사용한다.
- 다른 Application의 존재하는 Content Provider에 엑세스하기 위해
- 나의 Application의 데이터를 다른 Application과 공유하기 위해
Content Provider는 외부 Application에 데이터를 표시하는데 이는 관계형 데이터베이스의 테이블과 비슷한 하나 이상의 테이블로 나타낸다. 행은 Provider가 수집하는 유형의 데이터 인스턴스를 나타내며, 행에 있는 각 열은 인스턴스에 대해 수집된 개별적인 데이터를 나타낸다.
- Provider 엑세스
- Content Provider에 있는 데이터에 엑세스하려면, Application Context의 ContentResolver 오브젝트를 사용해 클라이언트와 통신한다.
- ContentResolver 오브젝트는 Provider 오브젝트(ContentProvider를 상속받은 클래스)와 통신한다.
- Provider 오브젝트가 클라이언트로부터 데이터 요청을 받으면 해당 내용을 수행하고 결과를 리턴한다.
- 이 오브젝트는 Provider 오브젝트(ContentProvider를 상속받은 클래스 중 하나의 인스턴스)에서 동일한 이름의 메서드를 호출하는 메서드를 갖고 있다.
- ContentResolver 메서드는 기본적인 “CRUD”(Create, Retrieve, Update, Delete) 기능을 제공한다.
- Content URI
- Provider에서 데이터를 식별하는 URI로 전체 Provider의 상징적인 이름(권한)과 테이블을 가리키는 이름(경로)이 포함된다.
- Provider 내의 테이블에 액세스하기 위해 클라이언트 메서드를 호출하는 경우, 그 테이블에 대한 Content URI 는 인수 중 하나이다.
- ContentResolver 오브젝트가 URI의 권한을 파싱한 다음, 이를 이용해 Provider를 확인한다. 즉, 이 권한을 알려진 Provider로 이뤄진 시스템 테이블과 비교하는 것이다. 그러면 ContentResolver가 쿼리 인수를 올바른 제공자에게 보낼 수 있다.
- ContentProvider는 Content URI의 경로를 사용하여 액세스할 테이블을 선택한다.
- ex) content://user_dictionary/words (user_dictionary : 권한, words : 테이블의 경로)
- 대부분의 Provider에서는 URI의 맨 끝에 ID값을 추가하면 테이블 내 하나의 행에 액세스 할 수 있다.
- ex) Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
- Provider에서 데이터 검색
- Provider에 대한 읽기 권한을 요청한다.
- Provider에게 쿼리를 보내는 코드를 정의한다.
- 읽기 액세스 권한 요청
- Provider에서 데이터를 검색하려면 Application에 해당 Provider에 대한 읽기권한이 필요하다. 따라서 Manifest에서 필요한 권한을 나타내야 한다. 이때, <uses-permission> 요소와 Provider가 정의한 정확한 권한 이름을 사용하면 된다.
- Android 6.0(API 23)부터는 런타임에 권한요청을 해야 한다.
- 쿼리 구성
- ContentResolver.query() 사용은 기본적으로 SQL 쿼리와 비슷하며, 반환할 열 집합과 선택 기준 집합, 그리고 정렬 순서가 이 안에 들어있다.
파라미터 |
타입 |
설명 |
uri |
@NonNull Uri |
검색할 내용이 있는 스키마에 대한 URI |
projection |
String[] |
리턴받을 컬럼값에 대한 리스트 null값일 경우 모든 컬럼에 대해 검색 |
selection |
String |
리턴받을 로우값에 대한 필터링 (SQL의 WHERE절) null값일 경우 모든 로우값 리턴 |
selectionArgs |
String[] |
‘?’의 값을 받아 직접 바인딩됨 |
sortOrder |
String |
로우값에 대한 정렬(SQL의 ORDER BY절) null값일 경우 기본정렬 |
cancellationSignal |
CancellationSignal |
실행 중 중단 신호를 보냄 (OperationCanceledException 을 던짐) null값일 경우 신호없음 |
- 악의적인 입력에 대한 보호
- ‘?’를 대체 가능한 매개변수로 사용하는 selection 절과 별도의 selctionArgs를 사용하여 사용자 입력이 SQL에 반영될 때 직접 바인드된다.
- ex)
- String mSelectionClause = “var = ?”;
- String[] mSelectionArgs = {“”};
- mSelectionArgs[0] = mUserInput;
- 쿼리 결과 표시
- ContentResolver.query() 메서드는 쿼리 선택 기준과 일치하는 행에 대해 projection에 지정한 열을 포함하는 Cursor를 반환한다. Cursor 객체가 데이터에 대한 읽기 액세스를 제공한다.
- 쿼리 선택 기준과 일치하는 행이 없으면 provider는 Cursor객체를 반환하며, Cursor.getCount()는 0(빈 커서)이다.
- Cursor는 행의 리스트이므로 Cursor의 내용을 표시하는 좋은 방법은 SimpleCursorAdapter를 통해 ListView에 연결하는 것이다.
- 쿼리 결과에서 데이터 가져오기
- 쿼리 결과에서 단순히 데이터를 표시하는 것 외에 결과값을 다른 작업에 사용할 수 있다.
- ex) 사용자 사전에서 철자를 검색한 다음 이것을 다른 provider에서 검색
- Cursor에 있는 get메서드를 활용하면 여러 가지 유형의 데이터를 검색할 수 있다.
- 쿼리 결과에서 단순히 데이터를 표시하는 것 외에 결과값을 다른 작업에 사용할 수 있다.
- Content Provider 권한
- Provider의 애플리케이션에서는 다른 애플리케이션이 데이터에 액세스할 때 반드시 가져야 할 권한을 지정할 수 있다. 이와 같은 권한을 통해 애플리케이션이 어느 데이터에 액세스를 시도할지 알 수 있다.
- 애플리케이션은 Provider의 요구사항을 근거로 액세스에 필요한 권한을 요청한다. 최종적으로 사용자는 애플리케이션을 설치할 때 요청된 권한을 보게 된다.
- 데이터 삽입
- 데이터를 Provider 안으로 삽입하려면, ContentResolver.insert() 메서드를 호출한다.
- 이 메서드는 Provider에 새로운 행을 삽입하고 해당 열에 대한 Content URI를 반환한다.
- 반환된 Uri에서 _ID값을 가져오려면 ContentUris.parseId()를 호출하면 된다.
- 새로운 행에 대한 데이터는 단일 행 커서와 형태가 유사한 단일 ContentValues 객체로 이동한다.
- 이 객체내의 열은 모두 같은 데이터 타입을 가지지 않아도 되며, 값을 지정하고 싶지 않은 경우 열을 null로 설정할 수 있다. 이때 ContentValues.putNull()을 사용한다.
- 데이터 업데이트
- 행을 업데이트하려면 업데이트된 값과 함께 ContentValues 객체를 사용한다. 이때 값은 삽입할 때의 값과 같고, 선택 기준은 쿼리와 동일하다.
- 사용하는 메서드는 ContentResolver.update()이다.
- 값을 추가하는 것은 업데이트 중인 열에 대한 ContentValues 객체만 하면 된다.
- 열의 내용을 비우고 싶으면 값을 null로 설정하면 된다.
- ContentResolver.update()를 호출할 경우엔 사용자 입력을 삭제하여 악의적인 입력에 대해 보호한다.
- 데이터 삭제
- 행을 삭제하는 것은 데이터를 검색하는 것과 비슷하다. 즉, 삭제하고자 하는 행에 대한 선택 기준을 지정하면 클라이언트 메서드가 삭제된 행 수를 반환한다.
- ContentResolver.delete() 메서드를 사용하면 되고, 마찬가지로 사용자 입력을 삭제하여 악의적인 입력에 대해 보호해야 한다.
- Provider 데이터 타입
- Integer, Float, String, Binary Large Object(BLOB)
- Provider 액세스에 대한 다른 형식
- 일괄 액세스(Batch access) : Provider에 일괄 액세스하면 많은 수의 행을 삽입할 때, 같은 메서드 호출 내에서 여러 개의 테이블에 여러 행을 삽입할 때 또는 전반적으로 프로세스 경계를 가로질러 일련의 작업을 수행하는 경우(원자성 작업) 유용하다.
- ContentProviderOperation 객체의 배열을 생성
- Content Provider에게 ContentResolver.applyBatch()로 발송
- 이 메서드는 특정 Content URI가 아니라 Content Provider의 권한을 전달한다. 그러면 배열 내의 각 ContentProviderOperation 객체가 서로 다른 테이블에 대해 작용하도록 할 수 있다.
- 비동기식 쿼리(Asynchronous queries)
- CursorLoader 객체를 사용하여 쿼리를 별도의 쓰레드에서 수행하도록 하는 방법이다.
- 인텐트를 통한 데이터 액세스(Data access via intent)
- 인텐트는 Content Provider에 간접 액세스를 제공할 수 있다.
- 애플리케이션에 액세스 권한이 없는데도 사용자에게 제공자내의 데이터에 액세스 권한을 허가하려면, 권한을 가지고 있는 애플리케이션에서 결과 인텐트를 다시 가져오거나 권한이 있는 애플리케이션을 활성화한 다음 사용자에게 그 애플리케이션에서 작업하도록 하면 된다.
- 임시권한으로 액세스하기
- 적절한 액세스 권한이 없더라도 Content Provider내의 데이터에 액세스할 수는 있다. 권한을 가지고 있는 애플리케이션에 인텐트를 보내 “URI”권한이 들어 있는 결과 인텐트를 돌려받으면 된다. 해당 권한은 특정 Content URI에 대한 권한으로, 이를 수신하는 액티비티가 완료될 때까지 유지된다. 권한이 있는 애플리케이션은 결과 인텐트에 다음과 같은 플래그를 설정하여 임시 권한을 허가한다.
- FLAG_GRANT_READ_URI_PERMISSION : 읽기 권한
- FLAG_GRANT_WRITE_URI_PERMISSION : 쓰기 권한
- 적절한 액세스 권한이 없더라도 Content Provider내의 데이터에 액세스할 수는 있다. 권한을 가지고 있는 애플리케이션에 인텐트를 보내 “URI”권한이 들어 있는 결과 인텐트를 돌려받으면 된다. 해당 권한은 특정 Content URI에 대한 권한으로, 이를 수신하는 액티비티가 완료될 때까지 유지된다. 권한이 있는 애플리케이션은 결과 인텐트에 다음과 같은 플래그를 설정하여 임시 권한을 허가한다.
- 다른 어플리케이션 사용
- 해당 권한을 가지고 있는 애플리케이션을 활성화한 후 사용자에게 그곳에서 작업하도록 해주는 방법이다.
- Contract Class : 애플리케이션이 Content URI, 로우 명, 인텐트 작업 및 Content Provider의 다른 기능과 작업할 수 있게 도와주는 상수를 정의한다.
- 일괄 액세스(Batch access) : Provider에 일괄 액세스하면 많은 수의 행을 삽입할 때, 같은 메서드 호출 내에서 여러 개의 테이블에 여러 행을 삽입할 때 또는 전반적으로 프로세스 경계를 가로질러 일련의 작업을 수행하는 경우(원자성 작업) 유용하다.
참고링크 :
https://developer.android.com/guide/topics/providers/content-providers
'안드로이드 > Guide' 카테고리의 다른 글
안드로이드 개발 - (8) View의 Listener 활용 - OnClickListener, OnLongClickListener (0) | 2020.04.10 |
---|---|
안드로이드 개발 - (7) View, ViewGroup, Inflation의 개념 (0) | 2020.04.09 |
안드로이드 개발 - (5) Android Component: Broadcast Receiver (0) | 2020.03.05 |
안드로이드 개발 - (4) Android Component: Service (0) | 2020.03.04 |
안드로이드 개발 - (3) Android Component: Activity (0) | 2020.03.03 |