콘텐츠 제공자 만들기

콘텐츠 제공자는 중앙 저장소로의 데이터 액세스를 관리합니다. 사용자는 제공자를 Android 애플리케이션에서 하나 이상의 클래스로 지정하고, 매니페스트 파일에 있습니다 클래스 중 하나가 ContentProvider - 제공자와 애플리케이션 사이의 인터페이스 사용할 수 있습니다

콘텐츠 제공자가 데이터를 다른 사람들에게 제공하고 애플리케이션에 활동이 있으면 사용자가 제공자가 관리하는 데이터를 쿼리하고 수정할 수 있습니다.

이 페이지에는 콘텐츠 제공자와 목록을 빌드하기 위한 기본 프로세스가 포함되어 있습니다. 다양한 API를 제공합니다

빌드를 시작하기 전에

제공자를 빌드하기 전에 우선 다음 단계를 고려하세요.

  • 콘텐츠 제공업체가 필요한지 결정합니다. 콘텐츠를 제작해야 하는 경우 제공업체로 전환할 수 있습니다. <ph type="x-smartling-placeholder">
      </ph>
    • 다른 애플리케이션에 복잡한 데이터나 파일을 제공하고자 하는 경우
    • 사용자가 복잡한 데이터를 내 앱에서 다른 앱으로 복사할 수 있게 하려고 합니다.
    • 검색 프레임워크를 사용한 사용자 지정 검색 제안을 제공하고자 하는 경우
    • 애플리케이션 데이터를 위젯에 노출하고자 하는 경우
    • AbstractThreadedSyncAdapter를 구현하려고 합니다. CursorAdapter 또는 CursorLoader 있습니다.

    데이터베이스 또는 다른 유형의 자체 애플리케이션 내에서만 사용하는 경우 영구 스토리지 위에 나열된 기능은 필요하지 않습니다. 대신 다음 페이지에 설명된 스토리지 시스템 중 하나를 사용해야 합니다. 데이터 및 파일 저장소 개요.

  • 아직 읽지 않은 경우 다음을 참조하세요. <ph type="x-smartling-placeholder"></ph> 콘텐츠 제공자 기본사항에서 제공자 및 제공자 작동 방식을 자세히 알아보세요.

그런 다음, 다음 단계를 따라 제공자를 빌드하세요.

  1. 데이터를 위한 원시 저장소를 설계합니다. 콘텐츠 제공자는 두 가지 방식으로 데이터를 제공합니다. <ph type="x-smartling-placeholder">
    </ph>
    파일 데이터
    일반적으로 다음과 같은 파일에 들어가는 데이터 사진, 오디오 또는 동영상입니다. 파일을 애플리케이션의 비공개로 저장합니다. 있습니다. 다른 애플리케이션의 파일 요청에 대한 응답으로, 제공업체가 파일에 핸들을 제공할 수 있습니다.
    '구조적' 데이터
    일반적으로 데이터베이스, 배열 또는 유사한 구조에 들어가는 데이터입니다. 행 및 열 테이블과 호환되는 형식으로 데이터를 저장합니다. 행 사람이나 인벤토리의 항목과 같은 항목을 나타냅니다. 열은 개인 이름 또는 품목 가격과 같은 엔터티에 대한 일부 데이터일 수 있습니다. 일반적으로 SQLite 데이터베이스에 저장된다는 것은 사실이지만, 모든 유형의 데이터를 사용할 수 있습니다 사용 가능한 저장소 유형에 대한 자세한 내용은 자세한 내용은 데이터 저장소 설계 섹션을 참조하세요.
  2. ContentProvider 클래스의 구체적인 구현을 정의합니다. 필수 메서드입니다. 이 클래스는 데이터와 나머지 애플리케이션 사이의 인터페이스입니다. Android 시스템 이 클래스에 대한 자세한 내용은 ContentProvider 클래스 구현 섹션.
  3. 제공자의 권한 문자열, 콘텐츠 URI, 열 이름을 정의합니다. 원하는 경우 제공자의 애플리케이션이 인텐트를 처리하고 인텐트 작업, 추가 데이터, 사용할 수 있습니다 gcloud 명령어를 사용하여 데이터에 액세스할 수 있습니다. 이러한 모든 값을 별도의 계약 클래스와 일치해야 합니다. 나중에 이 클래스를 다른 개발자에게 노출할 수 있습니다. 자세한 내용은 자세히 알아보려면 콘텐츠 URI 디자인 섹션 인텐트에 관한 자세한 내용은 인텐트 및 데이터 액세스 섹션.
  4. 샘플 데이터 또는 구현과 같은 다른 선택적 요소를 추가합니다. 데이터 동기화 가능한 AbstractThreadedSyncAdapter의 클라우드 기반 데이터를 지원합니다

데이터 저장소 설계

콘텐츠 제공자는 구조화된 형식으로 저장된 데이터로 연결되는 인터페이스입니다. 만들기 전에 데이터 저장 방법을 결정합니다. 데이터를 원하는 형식으로 그런 다음 필요에 따라 데이터를 읽고 쓰도록 인터페이스를 설계합니다.

다음은 Android에서 사용할 수 있는 데이터 저장소 기술 중 일부입니다.

  • 구조화된 데이터로 작업하는 경우 BigQuery와 같은 관계형 데이터베이스 또는 SQLite 또는 비관계형 키-값 데이터 스토어(예: LevelDB 일하는 경우 구조화되지 않은 데이터와 결합한 경우 데이터를 파일로 변환할 수 있습니다. 여러 유형의 스토리지를 혼합하고 노출할 수 있음 하나의 콘텐츠 제공자를 사용해야 합니다.
  • Android 시스템은 Room 지속성 라이브러리와 상호작용할 수 있습니다. Android의 자체 제공자가 SQLite 데이터베이스 API에 액세스할 수 있도록 합니다. 저장하는 데 사용할 수 있습니다. 이를 사용하여 데이터베이스를 만들려면 서브클래스를 인스턴스화하고 <ph type="x-smartling-placeholder"></ph> RoomDatabase에 설명된 대로 Room을 사용하여 로컬 데이터베이스에 데이터 저장

    저장소를 구현하기 위해 데이터베이스를 사용할 필요는 없습니다. 제공업체 관계형 데이터베이스와 유사하게 외부적으로 테이블 집합으로 나타나지만 제공자의 내부 구현에 대한 요구사항이 아닙니다.

  • 파일 데이터 저장의 경우, Android에는 다양한 파일 지향적 API가 있습니다. 파일 저장소에 대한 자세한 내용은 데이터 및 파일 저장소 개요. 만약 음악이나 동영상과 같은 미디어 관련 데이터를 제공하는 제공업체를 설계하는 경우 테이블 데이터와 파일을 결합하는 제공자가 있습니다.
  • 드물기는 하지만 하나 이상의 콘텐츠 제공자를 구현하는 것이 애플리케이션을 실행할 수 있습니다 예를 들어, 다른 콘텐츠 제공자와 공유하기 위해 다른 데이터 세트를 노출 애플리케이션을 실행할 수 있습니다
  • 네트워크 기반 데이터로 작업하려면 java.net의 클래스를 사용하고 android.net입니다. 또한 네트워크 기반 데이터를 로컬 데이터와 동기화할 수 있습니다. 저장한 다음 데이터를 테이블이나 파일로 제공하게 됩니다.

참고: 소스 코드에 포함되지 않은 변경사항을 이전 버전과 호환되므로 저장소를 새 버전으로 표시해야 함 있습니다. 또한 해당 업데이트를 실행하는 앱의 버전 번호도 새 콘텐츠 제공자를 구현합니다. 이렇게 변경하면 시스템을 다시 설치하려고 할 때 시스템을 비정상 종료하지 않도록 앱이 포함되어 있지 않습니다.

데이터 설계 시 고려할 사항

다음은 제공자의 데이터 구조를 설계하기 위한 몇 가지 팁입니다.

  • 테이블 데이터에는 항상 '기본 키'가 있어야 합니다. 한 개의 컨테이너가 있는 경우 를 각 행에 고유한 숫자 값으로 표현합니다. 이 값을 사용하여 행을 관련 행 (이를 "외래 키"로 사용) 어떤 이름이든 사용할 수 있지만 이 열의 경우 BaseColumns._ID을 사용하는 것이 가장 좋습니다. 왜냐하면 제공업체 쿼리의 결과를 ListView를 사용하려면 검색된 열 중 하나에 이름이 있어야 합니다. _ID입니다.
  • 비트맵 이미지나 다른 대용량 파일 지향 데이터를 제공하려면 데이터를 파일에 직접 저장하는 대신 간접적으로 제공 표에서 볼 수 있습니다. 이렇게 하면 제공업체의 사용자에게 ContentResolver 파일 메서드를 사용하여 데이터에 액세스합니다.
  • 바이너리 대형 객체 (BLOB) 데이터 유형을 사용하여 크기가 다르거나 설계되어 있습니다. 예를 들어 BLOB 열을 사용하여 프로토콜 버퍼 또는 JSON 구조.

    BLOB을 사용하여 스키마에 종속되지 않은 테이블을 구현할 수도 있습니다. 포함 이 유형의 테이블에서는 기본 키 열, MIME 유형 열 및 더 일반적인 열을 BLOB로 사용합니다. BLOB 열에 있는 데이터의 의미가 표시됩니다. MIME 유형 열의 값으로 나뉩니다. 이렇게 하면 다양한 행 유형을 살펴보겠습니다 연락처 제공자의 "데이터" 표 ContactsContract.Data는 스키마와 상관없는 스키마의 예입니다. 표에서 볼 수 있습니다.

콘텐츠 URI 설계

콘텐츠 URI는 제공자에서 데이터를 식별하는 URI입니다. 콘텐츠 URI에는 다음이 포함됩니다. 제공자 전체의 상징적인 이름 (제공업체의 기관)과 테이블 또는 파일을 가리키는 이름 (경로) 선택사항인 ID 부분은 개별 행입니다. 모든 데이터 액세스 방법은 ContentProvider에는 콘텐츠 URI가 인수로 있습니다. 이렇게 하면 액세스할 테이블, 행 또는 파일을 결정합니다.

콘텐츠 URI에 관한 자세한 내용은 <ph type="x-smartling-placeholder"></ph> 콘텐츠 제공자 기본사항

권한 설계

제공자에는 보통 하나의 권한이 있으며, 이것이 Android 내부 이름 역할을 합니다. 받는사람 다른 제공업체와의 충돌 방지, 인터넷 도메인 소유권 사용 (역방향) 을(를) 제공업체 권한의 기준으로 사용합니다. 이 권장사항은 Android에도 적용되므로 이름의 확장으로 제공자 권한을 정의할 수 있습니다. 이 메서드를 호출합니다.

예를 들어 Android 패키지 이름이 com.example.<appname>인 경우 제공업체에 기관 com.example.<appname>.provider.

경로 구조 설계

개발자는 일반적으로 권한으로부터 콘텐츠 URI를 생성할 때 개별 테이블만 선택하면 됩니다 예를 들어 table1이라는 테이블과 table2의 경우 이 요소를 이전 예의 권한과 결합하여 콘텐츠 URI com.example.<appname>.provider/table1com.example.<appname>.provider/table2입니다. 경로는 단일 세그먼트로 제한되며 경로의 각 수준에 대한 표가 필요하지 않습니다.

콘텐츠 URI ID 처리

제공자는 규칙에 따라 콘텐츠 URI를 수락하여 테이블의 단일 행에 대한 액세스를 제공합니다. 를 URI의 끝에 있는 행의 ID 값으로 바꿉니다. 또한 규칙에 따라 제공업체는 테이블의 _ID 열에 ID 값을 추가하고 행을 반환합니다.

이 규칙은 제공자에 액세스하는 앱을 위한 공통 설계 패턴을 세우는 데 유용합니다. 앱 제공자를 대상으로 쿼리를 실행하고 결과 Cursor를 표시합니다. CursorAdapter를 사용하여 ListView에서. CursorAdapter의 정의에는 다음 열의 열 중 하나가 필요합니다. Cursor이(가) _ID이(가) 됨

그러면 사용자는 UI에서 표시된 행 중 하나를 선택하여 데이터를 수집하는 데 사용됩니다 앱은 Cursor에서 상응하는 행을 가져와서 ListView: 이 행의 _ID 값을 가져와 다음에 추가합니다. 콘텐츠 URI를 만들고, 액세스 요청을 제공자에게 보냅니다. 그러면 제공업체는 쿼리 또는 수정을 사용자가 선택한 바로 그 행에 적용할 수 있습니다.

콘텐츠 URI 패턴

수신되는 콘텐츠 URI에 대해 어떤 작업을 수행할지 선택하는 데 도움이 되도록 제공자 API에는 콘텐츠 URI 패턴을UriMatcher 정수 값 switch 문에서 정수 값을 사용할 수 있습니다. 특정 패턴과 일치하는 콘텐츠 URI(하나 이상)에 대해 원하는 작업을 선택합니다.

콘텐츠 URI 패턴은 와일드카드 문자를 사용하는 콘텐츠 URI와 일치합니다.

  • *는 모든 길이의 모든 유효한 문자로 구성된 문자열과 일치합니다.
  • #는 모든 길이의 숫자 문자로 구성된 문자열과 일치합니다.

콘텐츠 URI 처리를 설계하고 코딩하는 예로, 다음 콘텐츠 URI를 인식하는 com.example.app.provider 권한 테이블 가리키기:

  • content://com.example.app.provider/table1: table1이라는 테이블입니다.
  • content://com.example.app.provider/table2/dataset1: dataset1입니다.
  • content://com.example.app.provider/table2/dataset2: dataset2입니다.
  • content://com.example.app.provider/table3: table3이라는 테이블입니다.

제공자는 행 ID가 추가된 경우 이러한 콘텐츠 URI도 인식합니다(예:content://com.example.app.provider/table3/1 table3에서 1

가능한 콘텐츠 URI 패턴은 다음과 같습니다.

content://com.example.app.provider/*
제공자에 있는 모든 콘텐츠 URI와 일치합니다.
content://com.example.app.provider/table2/*
dataset1 테이블의 콘텐츠 URI와 일치합니다. 및 dataset2이지만 table1 또는 dataset2의 콘텐츠 URI와 일치하지 않습니다. table3입니다.
content://com.example.app.provider/table3/#
콘텐츠 URI와 일치 table3의 단일 행(예: content://com.example.app.provider/table3/6: 다음으로 식별하는 행 6입니다.

다음 코드 스니펫은 UriMatcher에서 메서드의 작동 방식을 보여줍니다. 이 코드는 전체 테이블의 URI를 전체 테이블의 URI와 다르게 처리합니다. 콘텐츠 URI 패턴을 사용하여 단일 행 content://<authority>/<path>: 테이블 및 단일 행의 경우 content://<authority>/<path>/<id>

addURI() 메서드는 권한을 부여하는 데 사용될 수 있습니다. match() 메서드는 URI의 정수 값을 반환합니다. switch 문 전체 테이블 쿼리와 단일 레코드 쿼리 중에서 선택합니다.

Kotlin

private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
    /*
     * The calls to addURI() go here for all the content URI patterns that the provider
     * recognizes. For this snippet, only the calls for table 3 are shown.
     */

    /*
     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
     * in the path.
     */
    addURI("com.example.app.provider", "table3", 1)

    /*
     * Sets the code for a single row to 2. In this case, the # wildcard is
     * used. content://com.example.app.provider/table3/3 matches, but
     * content://com.example.app.provider/table3 doesn't.
     */
    addURI("com.example.app.provider", "table3/#", 2)
}
...
class ExampleProvider : ContentProvider() {
    ...
    // Implements ContentProvider.query()
    override fun query(
            uri: Uri?,
            projection: Array<out String>?,
            selection: String?,
            selectionArgs: Array<out String>?,
            sortOrder: String?
    ): Cursor? {
        var localSortOrder: String = sortOrder ?: ""
        var localSelection: String = selection ?: ""
        when (sUriMatcher.match(uri)) {
            1 -> { // If the incoming URI was for all of table3
                if (localSortOrder.isEmpty()) {
                    localSortOrder = "_ID ASC"
                }
            }
            2 -> {  // If the incoming URI was for a single row
                /*
                 * Because this URI was for a single row, the _ID value part is
                 * present. Get the last path segment from the URI; this is the _ID value.
                 * Then, append the value to the WHERE clause for the query.
                 */
                localSelection += "_ID ${uri?.lastPathSegment}"
            }
            else -> { // If the URI isn't recognized,
                // do some error handling here
            }
        }

        // Call the code to actually do the query
    }
}

자바

public class ExampleProvider extends ContentProvider {
...
    // Creates a UriMatcher object.
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        /*
         * The calls to addURI() go here for all the content URI patterns that the provider
         * recognizes. For this snippet, only the calls for table 3 are shown.
         */

        /*
         * Sets the integer value for multiple rows in table 3 to one. No wildcard is used
         * in the path.
         */
        uriMatcher.addURI("com.example.app.provider", "table3", 1);

        /*
         * Sets the code for a single row to 2. In this case, the # wildcard is
         * used. content://com.example.app.provider/table3/3 matches, but
         * content://com.example.app.provider/table3 doesn't.
         */
        uriMatcher.addURI("com.example.app.provider", "table3/#", 2);
    }
...
    // Implements ContentProvider.query()
    public Cursor query(
        Uri uri,
        String[] projection,
        String selection,
        String[] selectionArgs,
        String sortOrder) {
...
        /*
         * Choose the table to query and a sort order based on the code returned for the incoming
         * URI. Here, too, only the statements for table 3 are shown.
         */
        switch (uriMatcher.match(uri)) {


            // If the incoming URI was for all of table3
            case 1:

                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
                break;

            // If the incoming URI was for a single row
            case 2:

                /*
                 * Because this URI was for a single row, the _ID value part is
                 * present. Get the last path segment from the URI; this is the _ID value.
                 * Then, append the value to the WHERE clause for the query.
                 */
                selection = selection + "_ID = " + uri.getLastPathSegment();
                break;

            default:
            ...
                // If the URI isn't recognized, do some error handling here
        }
        // Call the code to actually do the query
    }

또 다른 클래스인 ContentUris는 작업을 위한 편의 메서드를 제공합니다. 콘텐츠 URI의 id 부분으로 바꿉니다. UriUri.Builder에는 기존 Uri 객체와 새 객체를 빌드하는 작업을 반복합니다.

ContentProvider 클래스 구현

ContentProvider 인스턴스가 액세스 관리 구조화된 데이터 세트에 쉽게 적용할 수 있습니다. 모든 양식 최종적으로 ContentResolver를 호출한 다음 구체적인 ContentProvider의 메서드를 사용하여 액세스 권한을 얻습니다.

필수 메서드

추상 클래스 ContentProvider는 구체적인 서브클래스의 일부로 구현해야 합니다. 이러한 메서드를 제외한 모든 메서드는 onCreate()는 클라이언트 애플리케이션에서 호출합니다. 액세스를 시도하고 있습니다.

query()
제공업체에서 데이터를 검색합니다. 인수를 사용하여 쿼리, 반환할 행과 열, 결과의 정렬 순서입니다. 데이터를 Cursor 객체로 반환합니다.
insert()
제공자에 새 행을 삽입합니다. 인수를 사용하여 사용할 열 값을 가져옵니다. 다음에 대한 콘텐츠 URI 반환: 행입니다.
update()
제공자의 기존 행을 업데이트합니다. 인수를 사용하여 테이블과 행 선택 업데이트된 열 값을 업데이트하고 가져올 수 있습니다. 업데이트한 행 개수를 반환합니다.
delete()
제공업체에서 행을 삭제합니다. 인수를 사용하여 삭제합니다. 삭제한 행 개수를 반환합니다.
getType()
콘텐츠 URI에 상응하는 MIME 유형을 반환합니다. 이 방법은 자세한 내용은 콘텐츠 제공업체 MIME 유형 구현 섹션을 참조하세요.
onCreate()
제공자를 초기화합니다. Android 시스템은 호출 직후에 이 메서드를 호출합니다. 제공자를 만듭니다. 제공업체가 생성되기 전에는 ContentResolver 객체가 이 객체에 액세스하려고 시도합니다.

이러한 메서드는 동일하게 이름이 지정된 ContentResolver 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다.

이러한 메서드를 구현하려면 다음을 고려해야 합니다.

  • onCreate()를 제외한 모든 메서드 는 한 번에 여러 스레드에서 호출할 수 있으므로 스레드로부터 안전해야 합니다. 배우기 위해 자세한 내용은 <ph type="x-smartling-placeholder"></ph> 프로세스 및 스레드 개요
  • onCreate()에서 긴 작업을 실행하지 마세요. 실제로 필요할 때까지 초기화 작업을 미뤄두세요. onCreate() 메서드 구현 섹션 에서 자세히 설명합니다.
  • 이러한 메서드는 반드시 구현해야 하지만, 코드는 다음과 같은 작업을 할 필요가 없습니다. 예상되는 데이터 유형을 반환합니다. 예를 들어 다른 애플리케이션이 일부 테이블에 데이터를 삽입하지 못하도록 insert() 및 돌아오는 항공편 0.

query() 메서드 구현

ContentProvider.query() 메서드는 Cursor 객체를 반환해야 합니다. 또는 객체가 있는 경우 실패하면 Exception이 발생합니다. SQLite 데이터베이스를 데이터로 사용하는 경우 Cursor SQLiteDatabase 클래스의 query() 메서드

쿼리와 일치하는 행이 없으면 Cursor을 반환합니다. getCount() 메서드가 0을 반환하는 인스턴스입니다. 쿼리 프로세스 중에 내부 오류가 발생한 경우에만 null를 반환합니다.

SQLite 데이터베이스를 데이터 저장소로 사용하지 않는 경우 구체적인 서브클래스 중 하나를 사용하세요. (총 Cursor개) 예를 들어 MatrixCursor 클래스는 각 행이 Object 인스턴스의 배열인 커서를 구현합니다. 이 수업에서는 addRow()를 사용하여 새 행을 추가합니다.

Android 시스템은 Exception와 통신할 수 있어야 합니다. 배포될 수 있습니다 Android가 이 작업을 할 수 있는 유용한 다음과 같은 예외가 있습니다. 다음과 같이 쿼리 오류를 처리합니다.

insert() 메서드 구현

insert() 메서드는 ContentValues의 값을 사용하여 새 행을 적절한 테이블에 추가합니다. 인수입니다. 열 이름이 ContentValues 인수에 없으면 공급자 코드나 데이터베이스에서 이 기본 값을 제공하려 할 수 있습니다. 사용할 수 있습니다

이 메서드는 새 행의 콘텐츠 URI를 반환합니다. 이를 구성하려면 새로운 행의 기본 키(일반적으로 _ID 값)를 테이블의 콘텐츠 URI에 전달합니다. withAppendedId()입니다.

delete() 메서드 구현

delete() 메서드 데이터 스토리지에서 행을 삭제할 필요가 없습니다. 동기화 어댑터를 사용 중인 경우 삭제된 행을 표시하는 것이 좋습니다. 'delete' 포함 행을 완전히 삭제하는 대신 플래그를 지정합니다. 동기화 어댑터는 공급자에서 삭제하기 전에 삭제된 행을 확인하고 서버에서 제거합니다.

update() 메서드 구현

update() 메서드는ContentValues insert() 및 동일한 selectionselectionArgs 인수 delete()ContentProvider.query() 이렇게 하면 이러한 메서드 간에 코드를 재사용할 수 있습니다.

onCreate() 메서드 구현

Android 시스템은 onCreate()를 호출합니다. 시작됩니다. 빠르게 실행되는 초기화만 수행 데이터베이스 생성과 데이터 로딩을 제공자가 실제로 데이터 요청을 수신합니다. Cloud SQL에서 긴 작업을 수행하는 경우 onCreate()을(를) 사용하면 시작되어야 합니다. 결과적으로, 제공자에서 다른 네트워크로의 응답 속도가 느려집니다. 애플리케이션을 실행할 수 있습니다

다음 두 스니펫은 ContentProvider.onCreate() 및 <ph type="x-smartling-placeholder"></ph> Room.databaseBuilder() 첫 번째 스니펫에는 ContentProvider.onCreate() 각 항목의 의미는 다음과 같습니다. 데이터베이스 객체가 빌드되고 데이터 액세스 객체에 대한 핸들이 생성됩니다.

Kotlin

// Defines the database name
private const val DBNAME = "mydb"
...
class ExampleProvider : ContentProvider() {

    // Defines a handle to the Room database
    private lateinit var appDatabase: AppDatabase

    // Defines a Data Access Object to perform the database operations
    private var userDao: UserDao? = null

    override fun onCreate(): Boolean {

        // Creates a new database object
        appDatabase = Room.databaseBuilder(context, AppDatabase::class.java, DBNAME).build()

        // Gets a Data Access Object to perform the database operations
        userDao = appDatabase.userDao

        return true
    }
    ...
    // Implements the provider's insert method
    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc.
    }
}

자바

public class ExampleProvider extends ContentProvider

    // Defines a handle to the Room database
    private AppDatabase appDatabase;

    // Defines a Data Access Object to perform the database operations
    private UserDao userDao;

    // Defines the database name
    private static final String DBNAME = "mydb";

    public boolean onCreate() {

        // Creates a new database object
        appDatabase = Room.databaseBuilder(getContext(), AppDatabase.class, DBNAME).build();

        // Gets a Data Access Object to perform the database operations
        userDao = appDatabase.getUserDao();

        return true;
    }
    ...
    // Implements the provider's insert method
    public Cursor insert(Uri uri, ContentValues values) {
        // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc.
    }
}

ContentProvider MIME 유형 구현

ContentProvider 클래스에는 MIME 유형을 반환하는 두 가지 메서드가 있습니다.

getType()
모든 제공자에 대해 구현하는 필수 메서드 중 하나입니다.
getStreamTypes()
제공자가 파일을 제공하는 경우 구현해야 하는 메서드입니다.

테이블의 MIME 유형

getType() 메서드는 콘텐츠에서 반환하는 데이터 유형을 설명하는 MIME 형식의 String입니다. URI 인수입니다. Uri 인수는 특정 URI가 아닌 패턴일 수 있습니다. 이 경우 학습합니다.

텍스트, HTML 또는 JPEG와 같은 일반적인 데이터 유형의 경우 getType()는 표준 해당 데이터의 MIME 유형입니다. 이러한 표준 유형의 전체 목록은 IANA MIME 미디어 유형 있습니다.

테이블 데이터의 행 또는 여러 행을 가리키는 콘텐츠 URI의 경우, 반품 가능, 수수료 getType() Android의 공급업체별 MIME 형식의 MIME 유형입니다.

  • 유형 부분: vnd
  • 하위유형 부분: <ph type="x-smartling-placeholder">
      </ph>
    • URI 패턴이 단일 행에 대한 경우: android.cursor.item/
    • URI 패턴이 2개 이상의 행에 대한 경우: android.cursor.dir/
  • 제공자별 부분: vnd.<name><type>

    <name><type>를 제공합니다. <name> 값은 전역적으로 고유합니다. <type> 값이 상응하는 URI마다 고유합니다. 학습합니다. <name>로는 회사 이름 또는 애플리케이션 Android 패키지 이름의 일부분을 삭제합니다. Kubernetes에 적합한 <type>는 URI입니다.

예를 들어 제공업체의 권한이 com.example.app.provider이라는 테이블을 노출하고 table1, table1의 여러 행에 대한 MIME 유형은 다음과 같습니다.

vnd.android.cursor.dir/vnd.com.example.provider.table1

table1의 단일 행의 MIME 유형은 다음과 같습니다.

vnd.android.cursor.item/vnd.com.example.provider.table1

파일의 MIME 유형

제공업체가 파일을 제공하는 경우 getStreamTypes() 이 메서드는 제공자가 사용하는 파일의 MIME 유형의 String 배열을 반환합니다. 반환할 수 있습니다. MIME 유형별로 제공하는 MIME 유형 필터링 filter 인수를 사용하여 클라이언트가 처리하고자 하는 MIME 유형만 반환하도록 합니다.

예를 들어 사진 이미지를 JPG 파일, PNG, GIF 형식이 지원됩니다. 애플리케이션이 필터 문자열 image/*를 사용하여 ContentResolver.getStreamTypes()를 호출하는 경우 '이미지'로 ContentProvider.getStreamTypes() 메서드가 다음 배열을 반환합니다.

{ "image/jpeg", "image/png", "image/gif"}

앱이 JPG 파일에만 관심이 있는 경우 ContentResolver.getStreamTypes(): 필터 문자열 *\/jpeg getStreamTypes()은 다음을 반환합니다.

{"image/jpeg"}

제공자가 필터 문자열에서 요청한 MIME 유형 중 어떤 것도 제공하지 않는 경우, getStreamTypes()null를 반환합니다.

계약 클래스 구현

계약 클래스는 public final 클래스로, 이 클래스는 URI, 열 이름, MIME 유형, 그리고 제공자와 관련된 기타 메타데이터입니다. 클래스 제공자와 다른 애플리케이션 간의 계약을 체결하기 위해 URI, 열 이름, 열의 실제 값이 변경되더라도 올바르게 액세스할 수 기타 등등

계약 클래스는 일반적으로 상수에 니모닉 이름을 가지기 때문에 개발자에게도 도움이 됩니다. 개발자가 열 이름이나 URI에 잘못된 값을 사용할 가능성이 줄어듭니다. Kubernetes는 Javadoc 문서를 포함할 수 있습니다. 통합 개발 환경, 즉 Android 스튜디오는 계약 클래스에서 상수 이름을 자동 완성하고 상수입니다.

개발자는 애플리케이션에서 계약 클래스의 클래스 파일에 액세스할 수 없지만 액세스할 수는 있습니다. 개발자가 제공하는 JAR 파일에서 응용 프로그램으로 정적으로 컴파일합니다.

ContactsContract 클래스와 중첩 클래스는 사용할 수 있습니다.

콘텐츠 제공자 권한 구현

Android 시스템의 모든 측면에 관한 권한 및 액세스는 다음에 자세히 설명되어 있습니다. 보안 도움말 데이터 및 파일 저장소 개요도 은 다양한 스토리지 유형에 적용되는 보안 및 권한을 설명합니다. 요약하면 중요한 요점은 다음과 같습니다.

  • 기본적으로 기기의 내부 저장소에 저장된 데이터 파일은 애플리케이션을 실행할 수 있습니다
  • 생성한 데이터베이스 SQLiteDatabase개는 애플리케이션을 실행할 수 있습니다
  • 기본적으로 외부 저장소에 저장하는 데이터 파일은 공개 상태이며 누구나 읽을 수 있습니다. 콘텐츠 제공업체를 사용하여 다른 애플리케이션에서 다른 API 호출을 사용하여 이를 읽고 쓸 수 있기 때문입니다.
  • 기기 내부에서 파일 또는 SQLite 데이터베이스를 열거나 생성하기 위한 메서드 호출 스토리지는 잠재적으로 다른 모든 애플리케이션에 대한 읽기 및 쓰기 액세스 권한을 모두 부여할 수 있습니다. 만약 내부 파일이나 데이터베이스를 제공자의 리포지토리로 사용하고 '모든 사람이 읽을 수 있음' 또는 'world-writeable' 액세스, 사용자 인증 정보, 데이터를 보호하지 않습니다 파일 및 데이터베이스에 대한 기본 액세스는 내부 저장소가 '비공개'입니다. 제공자의 리포지토리에서 이를 변경하지 마세요.

콘텐츠 제공자 권한을 사용하여 데이터에 대한 액세스를 제어하려면 다음 단계를 따르세요. 데이터를 내부 파일, SQLite 데이터베이스 또는 클라우드에 저장(예: 애플리케이션과 데이터베이스를 공유할 수 있고, 파일과 데이터베이스를 애플리케이션 전용으로 유지할 수 있습니다.

권한 구현

기본적으로 모든 애플리케이션은 제공자에서 읽거나 제공자에 쓸 수 있습니다. 이는 기본 데이터가 비공개: 기본적으로 제공자에는 권한이 설정되어 있지 않기 때문입니다. 이를 변경하려면 매니페스트 파일에서 속성이나 하위 요소를 사용하여 제공자에 대한 권한 설정 <provider> 요소의 요소 공급자 전체에 적용되는 권한을 설정할 수 있습니다. 또는 세 가지 모두에 적용할 수 있습니다.

하나 이상을 사용하여 제공자의 권한을 정의합니다. 매니페스트 파일의 <permission> 요소 이 권한이 없다면 android:name 속성 예를 들어 읽기 권한의 이름을 지정합니다. com.example.app.provider.permission.READ_PROVIDER

다음 목록은 제공자 권한의 범위를 설명합니다. 권한이 점점 더 세분화될 것입니다. 보다 세분화된 권한이 범위가 큰 권한보다 우선 적용됩니다.

단일 읽기-쓰기 제공자 수준 권한
전체 제공자에 대한 읽기 및 쓰기 액세스를 모두 제어하는 권한 1개(지정된 경우) android:permission 속성을 <provider> 요소
읽기 및 쓰기 제공자 수준의 별도 권한
제공자 전체에 대한 읽기 권한과 쓰기 권한입니다. 사용자가 직접 android:readPermission android:writePermission 속성 <provider> 요소 이러한 정책은 다음에서 요구하는 권한보다 우선 적용됩니다. android:permission
경로 수준 권한
제공자의 콘텐츠 URI에 대한 읽기, 쓰기 또는 읽기/쓰기 권한입니다. 직접 지정 제어하려는 각 URI의 다음의 하위 요소 <path-permission>개: <provider> 요소 지정하는 각 콘텐츠 URI에 대해 읽기/쓰기 권한, 읽기 권한, 쓰기 권한 중 하나 또는 이 세 가지 모두 가능합니다. 읽기 및 쓰기 권한이 읽기/쓰기 권한보다 우선합니다. 또한 경로 수준은 권한은 제공자 수준 권한보다 우선합니다.
임시 권한
애플리케이션이 임시 액세스를 허용하는 권한 수준입니다. 에는 일반적으로 필요한 권한이 없습니다. 임시 애플리케이션 액세스 기능을 사용하면 애플리케이션이 kube-APIserver입니다 임시 권한을 사용하도록 설정하면 제공자에 대한 영구적인 권한은 해당 서비스의 모든 것에 지속적으로 액세스하는 데이터를 수집하는 데 사용됩니다

예를 들어 이메일 제공업체와 앱을 구현하고 있으며 외부 이미지 뷰어 애플리케이션이 사진 첨부 파일을 표시하도록 하려면 제공업체 권한을 요청하지 않고 이미지 뷰어에 필요한 액세스 권한을 부여하려면 사진의 콘텐츠 URI에 임시 권한을 설정할 수 있습니다.

다음과 같이 이메일 앱을 설계하세요. 사용자가 사진을 표시하려고 하면 앱이 사진의 콘텐츠 URI와 권한 플래그를 이미지 뷰어에 제공합니다. 이미지 뷰어에서 수행할 수 있는 작업 비록 뷰어가 사진을 가져오지 않았더라도 이메일 제공자에 사진을 제공자에 대한 일반적인 읽기 권한이 있어야 합니다.

임시 권한을 사용 설정하려면 android:grantUriPermissions 속성 요소 <provider>개 또는 하나 이상 추가 하위 요소 <grant-uri-permission>개를 <provider> 요소 전화걸기 Context.revokeUriPermission() - 임시 권한과 연결된 콘텐츠 URI에 대한 지원을 제공업체

속성 값에 따라 제공자에 액세스 가능한 정도가 결정됩니다. 이 속성을 "true"로 설정하면 시스템은 전체 제공자에 대한 권한이며, 이 권한이 필요한 다른 모든 권한은 재정의됩니다. 제공자 수준 또는 경로 수준 권한으로 대체될 수 있습니다.

이 플래그가 "false"로 설정된 경우 다음을 추가합니다. <grant-uri-permission> 하위 요소를 <provider> 요소 각 하위 요소는 콘텐츠 URI 또는 임시 액세스 권한이 부여된 URI입니다.

애플리케이션에 임시 액세스 권한을 위임하려면 인텐트에 FLAG_GRANT_READ_URI_PERMISSION 플래그, FLAG_GRANT_WRITE_URI_PERMISSION 플래그 또는 둘 다입니다. 이러한 setFlags() 메서드로 설정됩니다.

android:grantUriPermissions 속성이 없는 경우 "false"입니다.

<provider> 요소

ActivityService 구성요소와 같이 ContentProvider의 서브클래스 애플리케이션의 매니페스트 파일에서 <provider> 요소 Android 시스템은 요소:

권한 (android:authorities)
시스템 내에서 제공자 전체를 식별하는 상징적인 이름. 이 속성에 대한 자세한 내용은 콘텐츠 URI 디자인 섹션
제공자 클래스 이름 (android:name개)
ContentProvider를 구현하는 클래스입니다. 이 수업은 자세한 내용은 ContentProvider 클래스 구현 섹션.
권한
다른 애플리케이션이 액세스하기 위해 있어야 하는 권한을 지정하는 속성 제공자의 데이터: <ph type="x-smartling-placeholder">

권한과 그에 상응하는 속성은 자세한 내용은 콘텐츠 제공자 권한 구현 섹션.

시작 및 제어 특성
이 특성들은 Android 시스템이 제공자를 시작하는 방법과 시기를 결정하고, 제공자의 프로세스 특성 및 기타 런타임 설정 등입니다. <ph type="x-smartling-placeholder">
    </ph>
  • android:enabled: 시스템이 제공자를 시작할 수 있도록 하는 플래그입니다.
  • android:exported: 다른 애플리케이션이 이 제공자를 사용하도록 허용하는 플래그
  • android:initOrder: 이 제공자가 시작되는 순서입니다. 다른 제공업체와 비교하여
  • android:multiProcess: 시스템이 제공자를 시작할 수 있도록 하는 플래그입니다. 같은 프로세스에서
  • android:process: 제공자가 실행되는 프로세스의 이름
  • android:syncable: 제공자의 데이터가 다음과 같음을 나타내는 플래그입니다. 서버의 데이터와 동기화됨

이러한 속성은 <provider> 요소

정보성 특성
제공자의 선택적 아이콘과 레이블입니다. <ph type="x-smartling-placeholder">
    </ph>
  • android:icon: 제공자의 아이콘이 포함된 드로어블 리소스입니다. 아이콘은 설정 > > 전체.
  • android:label: 제공업체, 또는 둘 다일 수 있습니다. 라벨은 설정 > > 전체.

이러한 속성은 <provider> 요소

참고: Android 11 이상을 타겟팅하는 경우 패키지 공개 상태 문서 추가 구성이 필요합니다

인텐트 및 데이터 액세스

애플리케이션은 Intent를 사용하여 간접적으로 콘텐츠 제공자에 액세스할 수 있습니다. 애플리케이션이 ContentResolver 또는 ContentProvider입니다. 대신 활동을 시작하는 인텐트를 전송합니다. 이는 제공자 자체 애플리케이션의 일부인 경우가 많습니다. 대상 활동이 담당하는 UI에서 데이터를 검색하고 표시하는 것입니다.

인텐트의 작업에 따라 대상 활동이 사용자에게 제공자의 데이터를 수정하라는 메시지를 표시할 수도 있습니다. 인텐트에 'extras'가 포함될 수도 있음 대상 활동이 표시하는 데이터 사용할 수 있습니다. 그런 다음 사용자는 이 데이터를 변경하여 있습니다.

인텐트 액세스를 사용하여 데이터 무결성을 지원할 수 있습니다. 공급업체의 영향을 받을 수 있음 엄격히 정의된 비즈니스 로직에 따라 데이터를 삽입, 업데이트 및 삭제하는 것에 중점을 두고 있습니다. 만약 다른 애플리케이션이 데이터를 직접 수정하도록 허용하면 잘못된 데이터일 수 있습니다.

개발자들에게 인텐트 액세스 사용을 허용하려면, 그 내용을 철저히 기록해두어야 합니다. 애플리케이션 UI를 사용하는 인텐트 액세스가 시도보다 나은 이유 설명 코드를 사용하여 데이터를 수정할 수 있습니다.

제공자의 데이터를 수정하고자 하는 수신되는 인텐트 처리도 다른 인텐트를 처리할 수 없습니다. 인텐트 사용에 관한 자세한 내용은 인텐트 및 인텐트 필터.

자세한 내용은 캘린더 제공자 개요