Android
 Computer >> コンピューター >  >> プログラミング >> Android

Androidでコンテンツプロバイダーから連絡先の電話番号を取得する方法

はじめに

この記事では、Androidアプリでコンテンツプロバイダー(Content Provider)を使って、端末内の連絡先から電話番号を取得する方法を解説します。

連絡先データへアクセスするには、ContactsContract を使ったクエリの発行に加えて、READ_CONTACTS 権限のランタイムリクエストが必要です。以下の手順では、連絡先の一覧を ListView に表示し、項目をタップすると対応する電話番号を Toast で表示するサンプルアプリを作成していきます。

ステップ1:新規プロジェクトの作成

Android Studioを起動し、メニューから「File」⇒「New Project」を選択して新しいプロジェクトを作成します。必要な項目をすべて入力してください。

ステップ2:レイアウトファイル(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:MainActivity.java の実装

src/MainActivity.java に以下のコードを追加します。

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<String> mobileArray;
    ArrayList<String> numberArray;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        numberArray = new ArrayList<>();

        // READ_CONTACTS権限が許可済みなら連絡先を取得、未許可なら権限をリクエスト
        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);

        // 項目タップ時に対応する電話番号をToastで表示
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                String number = numberArray.get(position);
                Toast.makeText(MainActivity.this, number,
                        Toast.LENGTH_LONG).show();
            }
        });
    }

    private void requestPermission() {
        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<String> 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;
    }
}

このコードのポイントは次のとおりです。

  • 権限チェック:READ_CONTACTS 権限が未許可の場合は requestPermissions() で許可ダイアログを表示します。
  • 連絡先の取得:getAllContacts() 内で ContentResolver.query() を使い、まず連絡先の一覧を取得します。さらに HAS_PHONE_NUMBER が 0 より大きい連絡先について、CONTACT_ID を条件に Phone.CONTENT_URI から電話番号を取り出しています。
  • 画面表示:ArrayAdapter で氏名の一覧を ListView にバインドし、項目タップ時には position に対応する電話番号を Toast で表示します。

ステップ4:AndroidManifest.xml への権限追加

AndroidManifest.xml に以下のコードを追加します。<uses-permission> タグによる READ_CONTACTS 権限の宣言は必須ですので、忘れずに記述してください。

<?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"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

アプリの実行と確認

それではアプリを実行してみましょう。実機のAndroid端末がパソコンに接続されている前提で進めます。Android Studioでプロジェクト内のアクティビティファイルを開き、ツールバーの「Run」アイコンをクリックしてください。対象デバイスとして接続中のモバイル端末を選択すると、端末に以下のような初期画面が表示されます。

Androidでコンテンツプロバイダーから連絡先の電話番号を取得する方法

続けてリストの項目をタップすると、選択した連絡先の電話番号が以下のように Toast で表示されます。

Androidでコンテンツプロバイダーから連絡先の電話番号を取得する方法

補足:現代的な実装について

本記事のサンプルは旧サポートライブラリ(support library)を使用していますが、現在のAndroid開発では AndroidX への移行が標準となっています。また、API 23以降では権限リクエストを registerForActivityResult(ActivityResultContracts.RequestPermission()) を使うことで、コールバックベースより簡潔に記述できます。連絡先アクセスはユーザーの個人情報に関わるため、不要な権限要求は避け、権限が拒否された場合のフォールバック処理も用意しておくことをおすすめします。

  1. AndroidでArrayBlockingQueueの先頭(head)要素を取得する方法を徹底解説

    実装例に入る前に、ArrayBlockingQueueについて理解しておきましょう。ArrayBlockingQueueは、配列によって実装された容量制限付きのブロッキングキューで、FIFO(First In First Out:先入れ先出し)方式で動作します。つまり、最初に追加された要素がキューに最も長く残り、最後に追加された要素が最も短い期間キューに存在することになります。この記事では、AndroidアプリでArrayBlockingQueueの先頭(head)要素を取得する方法を、ステップごとにわかりやすく解説します。実装手順ステップ1:新規プロジェクトの作成Android Studio

  2. Androidで電話番号のブロックを解除する方法【標準アプリ・Truecaller対応】

    誰かの連絡先をブロックした経験は、誰にでもあるのではないでしょうか。見知らぬ相手や、関係がこじれてしまった旧知の人など、理由はさまざまです。着信拒否機能のおかげで、私たちは平穏な日常を送ることができます。Androidで電話番号をブロックすると、その番号からの電話もSMSも届かなくなります。 しかし、時間が経つと気持ちが変わることもあります。「話す価値がない」と思っていた相手が、実はそれほど悪い人ではなかったと感じたり、関係を修復するためにもう一度チャンスを与えたいと思ったりすることもあるでしょう。そんなときに必要になるのが「ブロック解除」です。ブロックを解除しない限り、その相手に電話をかけた