안드로이드 네 가지 구성 요소의 화이트 에세이 항목 - 세부 콘텐츠 제공자 (콘텐츠 공급자)

콘텐츠 제공자

콘텐츠 공급자 소개

컨텐츠 공급자가 (콘텐츠 공급자) 주로 사용되는 다른 응용 프로그램 간의 기능 데이터 공유 , 그것은 할 수있는 메커니즘의 완전한 세트를 제공합니다 방문 데이터를 보장하는 동시에, 응용 프로그램이 다른 프로그램의 데이터에 액세스 할 수 있도록 보안 , 현재, 콘텐츠 공급자의 사용은 크로스 안드로이드 응용 프로그램 공유 데이터를 달성하기 위해 표준 방법입니다 .
- 공식 학습 콘텐츠를 제공하기 전에, 우리는 또 다른 매우 중요한 지식을 파악해야하는 안드로이드 런타임 권한을 학습 콘텐츠 제공, 우리는이 기술을 사용하기 때문에. 또한 지식 런타임 권한은 종종 우리의 미래 발전과 관련된 것, 따라서 지식의이 부분에는 작업에 단단히 파악해야한다 .

런타임 권한

시스템의 첫 번째 버전의 시작이 존재하고있다에서 안드로이드 권한 메커니즘은 새로운 일이 아니다. 그러나 사실, 안드로이드 권한 메커니즘을하기 전에 일반적으로 사용되는 소프트웨어는 매우 쉽게에서 특히 어떤 사람들은 분리 할 수 ​​있으며, 사용자 보안 및 개인 정보 보호 제한적 역할을 보호 재생 "Diandaqike." 이를 위해, 더 나은 사용자의 개인 정보 보호 및 보안을 보호하기 위해,이 기능이 작동 안드로이드 6.0 시스템 사용 권한에서 참조 안드로이드 개발 팀은,이 부분은 우리가 6.0 시스템에 도입 된 새로운 기능에 대해 자세히 배울 수 있습니다.

1.Android 권한 메커니즘은 상세

우리는 안드로이드 카운티 BroadcastTest 프로젝트에 관련 콘텐츠와 접촉하기 전에, 시스템에 액세스 및 네트워크 방송 부팅의 상태를 모니터하기 위해, 다음의 AndroidManifest.xml 파일에 선언이 그러한 권리를 추가 :

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

네트워크의 상태가 시스템에 액세스하고 방송 청취를 켜 때문에 사용자 장비 관련 보안 , 따라서, 문장의 AndroidManifest.xml 파일 권한에 추가해야합니다 그렇지 않으면 우리의 프로그램이 충돌 것 .
그래서,이 두 가지 권리 선언의 추가 후 어떤 영향이 최종 사용자를위한? 왜 사용자 장비 그것의 보안을 보호 할 수 있습니까?
사실, 주요 사용자는 사용자가 6.0 시스템보다 낮은 경우 한 손으로, 프로그램은 장치에 설치되어, 두 가지 방법으로 보호되고, 설치 인터페이스에서 장치 권한을 묻는 메시지가 표시됩니다 프로그램. 사용자가 프로그램 설치 여부를 결정하는 어떤 권리의 총 적용되는 프로그램을 알고 명확하게 할 수 있도록.
한편, 애플리케이션 관리 인터페이스에서 언제든지 사용자 수는 프로그램에 대한 사용 권한에 대한 모든 응용 프로그램을 볼 수 있습니다, 이러한 모든 권리는 프로그램의 전경에 적용 할 각 응용 프로그램이 표시되지 않는 것을 보장하기 위해, 성명은, 사용자의 눈에서 은폐 될 수있다 권한의 남용의 경우.
이 디자인 아이디어 권한 메커니즘은 당신이 허가를 신청하는 경우 그 사용자에 의해 인정되고, 실제로 매우 간단합니다, 당신은 다음, 당신이 신청하는 권리를 인정 설치를 거부하지 않는 경우는, 프로그램을 설치합니다.
그러나 이상은 우리가 권위의 일반적으로 사용되는 소프트웨어 광범위하게 남용의 많은없이 할 수 없기 때문에 현실이 그것을 말할 수있는 권한을 신청하기 전에 권한을보고하지 않을 경우, 사용 여부에 관계없이, 어쨌든, 결국 얻을 매우 잔인, 좋은 그것을 거부했기 때문에, 당신은 그것을 설치할 수 있습니다합니까? 이것은 우리의 "Diantaiqike을"라고 부릅니다.
문제의 확실히 인식 안드로이드 개발 팀은 다음 권한 기능을 실행 6.0 시스템을 추가했다. 즉, 사용자는 모든 응용 프로그램에 한 번 인증 권한이 있지만 허가를 다시 신청하기 위해 주어진 권한에 소프트웨어를 다시 사용할 수있을 때 소프트웨어를 설치할 필요가 없습니다. 예를 들어, 지리적 타겟팅 권위의 런타임 응용 프로그램에서 카메라 응용 프로그램이 직접 설치할 수 없습니다, 나는이 권한을 거부,하지만 난 아직도 예전처럼,이 응용 프로그램의 다른 기능을 사용할 수 있어야합니다 경우에도 마찬가지입니다.
물론, 모든 권한이 허가 된 사용자에 대해, 런타임에 적용하는 데 필요한 매우 성가신 유지했다. 안드로이드는 이제 두 개의 범주가 소유 한 모든 권리가 일반 권리위험 특권 . 엄밀히 말하면, 세 가지 범주가 있습니다 말하기, 우리가 도입하지 않는, 특별한 허가가있다.

  • 표준 : 능력은 사용자의 보안 및 개인 정보 보호에 대한 직접적인 위협이되지 않습니다 권리를 말한다, 응용 프로그램의이 부분에 대한 권한, 시스템은 자동으로 수동 조작에 갈 필요없이, 우리가 권한을 부여하는 데 도움이 될 것입니다.
  • 위험한 권리 : 그들은 수동으로 클릭하기 전에 권리 액세스에 대한 요청이 부분에 대한, 등 연락처 정보를 얻는 장치 위치, 위치 장비로, 사용자의 개인 정보를 만지거나 장치의 안전에 영향을 미칠 수는 사용자가 라이센스를 취득해야합니다 그렇지 않으면 프로그램이 해당 기능을 사용할 수 없습니다.

그래서 질문은 위험한 힘있는, 우리가 보통의 권한이 얼마나되는, 많은 특권인가? 때문에 위험 권한으로, 어려운 일이 아니다 권위의 위험에 더하여, 우리는 보통의 남아있는 모든 권리이며, 몇 가지 있었다.

당신이 권한을 사용할 때마다이 테이블의 범위 내에있는 경우, 권한이 표에없는 경우, 당신은, 실행시 대처 수있는 권한이 있어야 확인이 테이블에 갈 수 있습니다 만의 AndroidManifest.xml 파일이 필요합니다 이 권한 문에 대해 추가합니다.
또한, 각각의 위험이 권한은 그룹 권한에 속하는 테이블에 유의 권한은 실행 권한 동안 우리의 이름을 처리 할 때 사용하지만, 한 번 그 권리는 다른 모든 권한의 권한 그룹에 해당하는 사용자에게 권한을 부여하기로 합의합니다 또한 권한이 부여됩니다. 다음으로 우리는 프로그램이 실행 중일 때 결국 허가를 신청하는 방법에 대해 알아보세요.

2. 프로그램을 실행할 수있는 권한에 대한 응용 프로그램

새 프로젝트 RuntimePermissionTest, 단순화를 위해 우리는 CALL_PHONE을 소개하는이 권한을 사용합니다.
CALL_PHONE이 권한은 호출이 위험한 권위로 표시되어 사용자의 휴대 전화에 관련된 관세 문제 될 것으로 필요 선언하는 함수 호출을 작성하는 것입니다. 안드로이드 전에 6.0 시스템은 다음과 같이 레이아웃 파일을 수정 activity_main.xml, 함수 호출이 실제로 매우 간단 실현 출연 :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/make_call"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Make Call" />

</LinearLayout>

버튼 로직 호출을 트리거하기 위해 클릭 할 때 우리는 레이아웃 파일을 그냥 버튼을 정의합니다. 그런 다음 다음과 같이, MainActivity의 코드를 수정 :

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button makeCall = (Button) findViewById(R.id.make_call);
        makeCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Intent intent = new Intent(Intent.ACTION_CALL);
                    intent.setData(Uri.parse("tel:10086"));
                    startActivity(intent);
                } catch (SecurityException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

이것은 버튼의 클릭 이벤트에서 볼 수있는, 우리가 작업을 호출하는 내장 된 시스템입니다 Intent.ACTION_CALL로 지정된 행동의 의도 암시 적 의도를 구축, 데이터 섹션은 프로토콜 전화, 번호 지정 10,086이며, 권한이 여기에 선언해야합니다. 또한, 충돌을 방지하기 위해, 모든 작업은 예외 트랩 블록 사이에 배치된다.
그럼있는 다음과 같은 권리를 명시,의 AndroidManifest.xml 파일을 수정 :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.runtimepermissontest">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

우리는 함수가 성공적으로 달성 전화와 휴대 전화에서 안드로이드 6.0 시스템을보다가 제대로 작동에 있지만, 우리는 전화 시스템 버전 6.0 이상에서 실행하는 경우, 전화 걸기 버튼이 아닌 클릭합니다 효과는 인쇄 로그 로그 캣이 시간에 관찰되지 않았다.
오류 로그 "권한 거부"가,가 6.0 이후 및 실행 권한을 처리해야하는 위험한 권리의 사용에 시스템 이상, 금지 인한 결과의 허가에 볼 수있는 것을 우리에게 상기시켜줍니다.
그래서 여기에 우리는 다음과 같이이 문제를 해결 MainActivity의 코드를 수정하려고 온 :

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button makeCall = (Button) findViewById(R.id.make_call);
        makeCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE
                ) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission.CALL_PHONE },1);
                } else {
                    call();
                }
            }
        });
    }

    private void call() {
        try {
            Intent intent = new Intent(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:10086"));
            startActivity(intent);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.
                        PERMISSION_GRANTED) {
                    call();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }
}

과정을 완료 위의 코드는 권한의 특정 분석을 살펴 보자, 덮여 실행됩니다. 노골적으로 말하면, 런타임 핵심 역량이하는 위험한 작업을 수행 할 수있는 사용자가 실행 프로그램 중 우리 권한을 부여, 프로그램이 이러한 위험한 작업을 수행하는 장면을 호출 할 수 없습니다 . 따라서 첫 번째 단계는 사용자가 이미 우리에게 도움의 승인을 준 여부를 결정하는 것은 ContextCompat.checkSelfPermission () 방법이다 . checkSelfPermission () 메소드는 첫 번째 매개 변수는 상황이며, 두 개의 매개 변수를 받아이의 아무것도, 두 번째 매개 변수는 이름 호출자에게 권한 Manifest.permission.CALL_PHONE입니다 같은 특정 권한의 이름없는 말, 우리는 메소드의 반환을 사용 PackageManager.PERMISSION_GRANTED 값과 비교, 사용자는 그 사용자가 인증되지 인증 수단 동일 불평등 것을 의미한다.
당신이 승인 한 경우, 간단한, 직접 전화 여기에 우리가의 () 메서드 호출에 패키지의 논리를 호출, 거기에 논리 연산을 수행합니다. 권한이없는 경우에, 당신은 사용자의 승인을 요청 ActivityCompat.requestPermissions () 메서드를 호출 할 필요가 requestPermission () 메서드는 첫 번째 매개 변수는 활동의 인스턴스를 필요로 세 개의 매개 변수를 허용하고, 두 번째 매개 변수는 String 배열, 우리는 원하는 세번째 파라미터 네 배열 출원인의 권리로는, 여기에 1을 통과하는 유일한 값으로이를 요청.
전화가 requestPermission () 메소드를 통해되면, 시스템은 사용자가 다음에 동의하거나 상관없이 결국 onRequestPermissionResult (방법) 다시 떨어질 것이다 결과 어떤 종류의 액세스를위한 우리의 요청을 거부하지 선택할 수있는 대화 상자 허가 신청을 팝업하고, 허가한다 grantResult 매개 변수에 포장됩니다 결과. 여기에서 우리는 사용자가 동의하는 경우, 당신이 거절하면 당신은, 전화를 걸 전화 () 메서드를 호출 한 후 우리는 작업을 포기 할 수 있으며, 팝업 메시지가 실패, 최종 인증 결과를 결정해야합니다.
콘텐츠 공급자 - 지금 당신은 안드로이드에 대한 사용 권한에 관한 다양한 문제를 처리 할 수있는 능력을 가지고, 여기에 우리 모두는 장에 도착.

다른 프로그램의 데이터에 액세스하려면

콘텐츠 제공 업체는 일반적으로 두 가지 사용이

  • 해당 프로그램에서 데이터를 읽고 조작하는 기존 콘텐츠 공급자를 사용.
  • 외부 액세스 RO에 대한 액세스를 제공하는 우리의 프로그램의 데이터에 대한 자신 만의 콘텐츠 제공자를 만듭니다.
    그래서 우리는 시작하는 기존 콘텐츠 제공 업체의 사용을 시작으로 하나 그것을 하나를 배우기 시작. 응용 프로그램 콘텐츠가 제공하는 외부 데이터 액세스 인터페이스를 제공하는 경우, 다른 응용 프로그램은 데이터의이 부분에 액세스 할 수 있습니다. 안드로이드 시스템은 타사 응용 프로그램이 더 나은 기능을 달성하기 위해 데이터의이 부분을 최대한 활용할 수 있도록하는 전화 번호부, SMS, 미디어 라이브러리 및 다른 프로그램이 제공 유사한 액세스 인터페이스와 함께 제공됩니다. 여기에서 우리는 결국 콘텐츠 공급자를 살펴 그것을 사용하는 방법입니다 걸릴.

컨텐트 리졸버의 기본 사용법

컨텐트 리졸버 클래스를 통해 공유 할 수 있었다 각 응용 프로그램에 대해, 데이터는 콘텐츠 제공 업체에 액세스하려면, 당신은 방법이 사용되는 방법의 일련의 제공) (getContentResolver 컨텍스트에서 컨텐트 리졸버에 의해이 클래스의 인스턴스를 얻을 수 있습니다 데이터, 상기에 CRUD 연산 :

데이터를 추가하는 () 메소드를 삽입
데이터를 갱신하기위한 갱신 () 메소드를
삭제 () 메소드는 데이터 삭제하는 데 사용되는
방법은 데이터 조회하기 위해 사용되는 쿼리 ()
파라미터 테이블 이름으로 수신되지 않은 컨텐트 리졸버의 SQLiteDatabase 상이한를 CRUD 방법 대신 열린 우리당 매개 변수를 사용하지만,이 매개 변수는 내용 URI라고합니다. : 콘텐츠 데이터는 주로 두 부분으로 구성되는 콘텐츠에 고유 식별자를 설정하는 URI 용기 공급 기관경로 . 당국은 여러 응용 프로그램 사이의 구분을 위해 사용된다. 일반적으로 충돌을 피하려면 이름을 붙일 수있는 패키지 이름의 방법으로 될 것입니다. 예를 들어, 프로그램 패키지의 이름입니다 COM. Example.app, 다음 권한을 해당 프로그램이 지정됩니다 com.example.app.provider의
경로는 일반적으로, 다른 테이블에서 여러 응용 프로그램 사이의 구분을 위해 사용된다 기관의 후방에 추가. 예를 들어, 두 개의 테이블의 존재 데이터베이스 프로그램 : 표 1과 표 2는, 당신은 컨텐츠 URI는 com.example.app하게 결합 / 표 및 / 표 2, 다음의 권한과 경로 이름 PAH 수 있습니다 .provider / 표 및 com.example.app.provider / 표 2
그러나,이 두 문자열 우리는 또한 머리 문자열에 프로토콜 선언을 추가해야합니다,이 컨텐츠 URI이다 인식하는 매우 어려운 작업입니다. 다음과 같이 따라서 대부분의 표준 형식으로 기록 된 컨텐츠 URI는 다음과 같습니다

이 찾을 수없는, 컨텐츠 URI는 매우 우리가하는 장 테이블 액세스 데이터를 프로그램 할 것을 명확하게 할 수있다. 또한 왜, 추가하고 테이블 이름을 사용하는 경우, 시스템은 우리가 테이블의 응용 프로그램에 액세스 할 것으로 예상 알 수 없기 때문에 유일한 매개 변수로 열린 Object를 수신 할 컨텐트 리졸버 ContentResolver 검색 방법의 변화. URI를 문자열의 내용을 얻은 후에, 우리는 또한 인수로 전달 될 수있는 바이오 열린 객체로 구문 분석 할 필요가있다. 다음과 같이 분석 방법은 매우 간단합니다 :

Uri uri = Uri.parse("content://com.example.app.provider/table1")

다음과 같이 그냥 Uri.parse () 메서드를 호출, 내용이 URI 문자열 열린 객체로 구문 분석 할 수 있으며, 이제 우리는 테이블의 데이터를 조회하려면이 tablel에게 열린 개체를 사용할 수있는 코드는 다음과 같습니다

Cursor cursor = getContentResolver().query(
    uri, 
    projection,
    selection,
    selectionArgs,
    sortOrder);

이러한 매개 변수와의 SQLiteDatabase 쿼리 ()과 같은 매개 변수 방법, 그러나 전반적으로 다른 프로그램에서 간단 결국,이 액세스하는 데이터가 필요 너무 복잡한 쿼리를 작성하지 않는 것입니다. 파라미터의 일부에 사용되는 테이블을 상세히 설명한다.

쿼리의 반환이 완료 여전히 커서 오브젝트 후 커서는 한 개에 의해 하나의 객체에서, 우리는 데이터를 읽을 수 있습니다. 다음 아이디어는 여전히 해당 열의 각 행의 데이터를 삭제 한 다음 모든 행에 커서 위치를 통과하고, 커서를 이동시켜 판독한다 :

if(cursor != null){
    while(cursor.moveToNext()){
        String column1 = cursor.getString(cursor.getColumnIndex("column1"));
        int column2 =  cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}

가장 어려운 쿼리 작업, 추가의 나머지 부분, 수정 작업이 심지어 말할 것도 삭제를 마스터. 이제 코드는 다음과 같다 tablel하는 데이터 테이블을 추가하는 방법을 살펴 보자 :

ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2", 1);
getContentResolver().insert(uri, values);

또한 본 ContentValues ​​데이터에 추가 여전히 조립하고 파라미터 수있는 바와 같이, 삽입 컨텐트 리졸버 () 메소드는 URI와 ContentValues ​​후속 호출 할 수있다. 우리가이 새로 추가 된 데이터를 비우고, 컬럼의 값을 업데이트하려면 다음과 같이 이제 컨텐트 리졸버 업데이트 () 메소드를 구현 코드를 사용할 수있다 :

ContentValues values = new ContentValues();
values.put( "column1" , "" );
getContentResolver().update( uri, values, "column1 = ? and column2 = ?", new String[] { "text" , "1" } );

영향을받는 모든 행을 방지하기 위해, 위의 코드를 업데이트 할 제한 할 selectionArgs 선택과 데이터 매개 변수를 사용합니다. 마지막으로, 삭제 된 데이터를 넣어 삭제 () 메소드를 컨텐트 리졸버 호출 할 수 있습니다 다음과 같이 코드입니다 :

getContentResolver().delete( uri, "column2 = ?", new String[] { "1" } );

지금까지 우리는 최종 학교의 CRUD 메소드 컨텐트 리졸버를 넣어. 그럼, 우리가 지금까지 배운 지식을 사용하여 연락처 정보 시스템의 전화 번호부를 읽는 방법에 대하여 살펴 보도록하겠다.

연락 판독 시스템

첫째, 우리는 귀하의 휴대 전화에서 나는이 테스트 시스템에 아무런 접촉이 없기 때문에 다시 읽기 쉬운 상대를 추가 할 필요가 있으므로 여기에 우리가 두 가지를 추가, 연락처를 추가해야합니다. 다음으로, 새로운 ContactsTest 프로젝트를 만듭니다.
코드를 수정 Activity_main.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/contacts_view">
        
    </ListView>
    
</LinearLayout> 

리스트 뷰 레이아웃에 추가 된
코드 MainActivity의 수정 :

public class MainActivity extends AppCompatActivity {

    ArrayAdapter<String> adapter;
    List<String> contactsList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactsList);
        contactsView.setAdapter(adapter);
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);
        }else {
            readContacts();
        }
    }

    private void readContacts(){
        Cursor cursor = null;
        try{
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
            if(cursor != null){
                while(cursor.moveToNext()){
                    String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contactsList.add(displayName+"\n"+number);
                }
                adapter.notifyDataSetChanged();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (cursor != null){
                cursor.close();
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){
        switch (requestCode){
            case 1:
                if (grantResults.length > 0&& grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    readContacts();
                }else {
                    Toast.makeText(this,"You denied the permission",Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }
}

한 OnCreate () 메소드에서는 먼저리스트 뷰 컨트롤의 인스턴스를 얻고, 그것을 좋은 어댑터를 제공하고 READ_CONTACTS 권한이 위험한 권한입니다 때문에 처리 로직 권한 런타임을 호출하기 시작했다. 런타임 권한에 대한 프로세스 흐름은 예술을 마스터했다고 생각합니다. 연락처 정보를 읽는 사용자 인증 시스템 후 readContacts () 메서드를 호출합니다. 다음 하이라이트 readContacts 모양 () 메소드, 시스템 연락처 데이터를 조회하려면 여기를 쿼리 () 메소드의 컨텐트 리졸버 사용을 볼 수 있습니다. 그러나, 수신 열린 우리당 매개 변수는 이상한 아?ー콘텐츠 URI 문자열을 해결하기 위해 Uri.parse () 메소드를 호출하지 왜?이 ContactsContract.CommonDataKinds.Phone 클래스가 제공하는 패키지를 할 도움이되었습니다 있기 때문에 방법 일정한 CONTENT_URI,이 상수 () 메소드는 파싱 결과 Uri.parse의 사용이다. 그럼 한 제거 연락처 이름이 열에있는 연락처 이름에 대응하는 전화 번호 데이터에 의해, 커서 객체 중 하나를 통과 상수 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME이고,이 항목에서 연락처 전화 번호는 해당 상수 ContactsContract.CommonDatakinds이다. Phone.NUMBER. 이 데이터가 제거 된 후, 그들은 접합 된 다음의 ListView의 데이터 소스에 접합 데이터를 추가하고, 새로 고침 목록보기 통지합니다. 마지막으로, 커서 객체를 차단하는 것을 잊지 마세요.
이 매듭 동쪽 아직은? 아직도 수줍음, 시스템은 접촉 기관이 문을 잊어서는 안 읽습니다. AndroidManifest.xml에있는 코드를 수정 :

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

추천

출처www.cnblogs.com/AleiCui/p/11691035.html