Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

안드로이드 콘텐츠 프로바이더로 연락처 전화번호 가져오는 방법 (예제 코드)

개요

이 튜토리얼에서는 안드로이드에서 콘텐츠 프로바이더(Content Provider)를 활용해 기기에 저장된 연락처의 전화번호를 가져오는 방법을 단계별로 알아봅니다. 연락처 데이터는 ContactsContract를 통해 접근할 수 있으며, 이 과정에서는 반드시 READ_CONTACTS 권한이 필요합니다.

1단계 — 새 프로젝트 생성

Android Studio에서 File ⇒ New Project 메뉴로 이동한 후, 새 프로젝트를 만들기 위해 필요한 모든 정보를 입력해 프로젝트를 생성합니다.

2단계 — 레이아웃 작성 (res/layout/activity_main.xml)

아래 코드를 res/layout/activity_main.xml 파일에 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "https://schemas.android.com/apk/res/android"
    android:layout_width = "match_parent"
    android:gravity = "center"
    android:layout_height = "match_parent">
    <ListView
        android:id = "@+id/list"
        android:layout_width = "wrap_content"
        android:textSize = "30sp"
        android:layout_height = "wrap_content"
        android:text = "Click"/>
</LinearLayout>

위 코드에서는 화면 중앙에 연락처 목록을 표시할 ListView 하나를 배치했습니다.

3단계 — 메인 액티비티 작성 (src/MainActivity.java)

아래 코드를 src/MainActivity.java 파일에 추가합니다. 이 클래스는 연락처 읽기 권한을 확인·요청하고, 콘텐츠 프로바이더에서 이름과 전화번호를 조회한 뒤 목록 항목을 탭하면 해당 전화번호를 토스트(Toast)로 보여줍니다.

package com.example.myapplication;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    public static final int REQUEST_READ_CONTACTS = 79;
    ListView list;
    ArrayList mobileArray;
    ArrayList numberArray;
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        numberArray = new ArrayList();
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
            mobileArray = getAllContacts();
        } else {
            requestPermission();
        }
        list = findViewById(R.id.list);
        ArrayAdapter adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, android.R.id.text1, mobileArray);
        list.setAdapter(adapter);
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String number = (String) numberArray.get(position);
                Toast.makeText(MainActivity.this,number,Toast.LENGTH_LONG).show();
            }
        });
    }
    private void requestPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,android.Manifest.permission.READ_CONTACTS)) {
            // 필요하다면 여기에 권한 요청 사유를 설명하는 UI를 표시할 수 있습니다.
        } else {
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_CONTACTS},
            REQUEST_READ_CONTACTS);
        }
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_CONTACTS)) {
        } else {
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_CONTACTS},
            REQUEST_READ_CONTACTS);
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode,
    String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_READ_CONTACTS: {
                if (grantResults.length > 0  && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mobileArray = getAllContacts();
                } else {
                    // 권한이 거부된 경우, 이 권한에 의존하는 기능을 비활성화합니다.
                }
                return;
            }
        }
    }
    private ArrayList getAllContacts() {
        ArrayList<String> nameList = new ArrayList<>();
        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
        null, null, null, null);
        if ((cur != null ? cur.getCount() : 0) > 0) {
            while (cur != null && cur.moveToNext()) {
                String id = cur.getString(
                cur.getColumnIndex(ContactsContract.Contacts._ID));
                String name = cur.getString(cur.getColumnIndex(
                ContactsContract.Contacts.DISPLAY_NAME));
                nameList.add(name);

                if (cur.getInt(cur.getColumnIndex(
                    ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
                        Cursor pCur = cr.query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
                        new String[]{id}, null);
                        while (pCur.moveToNext()) {
                            String phoneNo = pCur.getString(pCur.getColumnIndex(
                                ContactsContract.CommonDataKinds.Phone.NUMBER));
                                numberArray.add(phoneNo);

                        }
                        pCur.close();
                }
            }
        }
        if (cur != null) {
            cur.close();
        }
        return nameList;
    }
}

코드 핵심 로직 정리

getAllContacts() 메서드가 이 예제의 핵심입니다. 동작 순서는 다음과 같습니다.

ContentResolverContacts.CONTENT_URI를 조회해 연락처 목록을 가져옵니다.
② 각 연락처의 _ID, DISPLAY_NAME을 읽어 이름 목록에 추가합니다.
HAS_PHONE_NUMBER 값이 0보다 크면, CommonDataKinds.Phone.CONTENT_URICONTACT_ID 조건으로 다시 조회해 전화번호를 추출합니다.
④ 사용이 끝난 커서(Cursor)는 반드시 close()로 닫아 리소스 누수를 방지합니다.

4단계 — 권한 선언 (AndroidManifest.xml)

연락처를 읽으려면 매니페스트에 권한 선언이 필수입니다. 아래 코드를 AndroidManifest.xml에 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
    package = "com.example.myapplication">
    <uses-permission android:name = "android.permission.READ_CONTACTS" />
    <application
        android:allowBackup = "true"
        android:theme = "@style/AppTheme.NoActionBar"
        android:icon = "@mipmap/ic_launcher"
        android:label = "@string/app_name"
        android:roundIcon = "@mipmap/ic_launcher_round"
        android:supportsRtl = "true">
        <activity
            android:name = ".MainActivity"
            android:configChanges = "keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name = "android.intent.action.MAIN" />
                <action android:name = "android.intent.action.CREATE_SHORTCUT" />
                <category android:name = "android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

앱 실행 및 결과 확인

이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘을 클릭하고, 옵션에서 자신의 모바일 기기를 선택하면 기기에 아래와 같은 기본 화면이 표시됩니다.

안드로이드 콘텐츠 프로바이더로 연락처 전화번호 가져오는 방법 (예제 코드)

목록에서 원하는 연락처 항목을 탭하면, 해당 연락처의 전화번호가 아래와 같이 토스트 메시지로 표시됩니다.

안드로이드 콘텐츠 프로바이더로 연락처 전화번호 가져오는 방법 (예제 코드)

참고 사항

위 예제는 구버전 android.support 라이브러리를 사용합니다. 최신 프로젝트라면 AndroidX 마이그레이션 후 androidx.core.app.ActivityCompatandroidx.appcompat.app.AppCompatActivity로 임포트를 교체하면 됩니다. 또한 API 23(마시멜로) 이상에서는 위와 같이 런타임 권한 요청이 반드시 필요하며, 성능과 유지보수를 고려한다면 ListView 대신 RecyclerView 사용도 권장됩니다.