このレッスンでは、次の手法を使用して、データが検索文字列の全体または一部と一致する連絡先のリストを取得する方法について説明します。
- 連絡先の名前を照合する
- 検索文字列を連絡先名データのすべてまたは一部と照合して、連絡先のリストを取得します。連絡先プロバイダでは、同じ名前の複数のインスタンスが許可されるため、この手法では一致する連絡先のリストが返される可能性があります。
- 特定の種類のデータ(電話番号など)を照合する
- 検索文字列をメールアドレスなどの特定の種類の詳細データと照合して、連絡先のリストを取得します。たとえば、この手法を使用すると、メールアドレスが検索文字列と一致するすべての連絡先を一覧表示できます。
- すべての種類のデータを照合する
- 検索文字列を名前、電話番号、番地、メールアドレスなどの詳細データと照合して、連絡先のリストを取得します。たとえば、この手法を使用すると、検索文字列として任意の種類のデータを受け入れ、その文字列に一致する連絡先を一覧表示できます。
注: このレッスンでは、すべての例で CursorLoader を使用して連絡先プロバイダからデータを取得します。CursorLoader は、UI スレッドとは別のスレッドでクエリを実行します。これにより、クエリによって UI の応答時間が遅くなり、ユーザー エクスペリエンスが低下することを防ぎます。詳しくは、Android トレーニング クラスの
バックグラウンドでのデータの読み込みをご覧ください。
プロバイダの読み取り権限をリクエストする
連絡先プロバイダに対してなんらかの検索を行うには、アプリに READ_CONTACTS 権限が必要です。この権限をリクエストするには、次の <uses-permission> 要素を <manifest> の子要素としてマニフェスト ファイルに追加します。
<uses-permission android:name="android.permission.READ_CONTACTS" />
連絡先を名前で照合して結果を一覧表示する
この手法では、検索文字列を、連絡先プロバイダの ContactsContract.Contacts テーブル内の 1 つまたは複数の連絡先の名前と照合しようとします。通常は、一致した連絡先をユーザーが選択できるように、結果を ListView に表示します。
ListView とアイテム レイアウトを定義する
検索結果を ListView に表示するには、ListView を含む UI 全体を定義するメイン レイアウト ファイルと、ListView の 1 行を定義するアイテム レイアウト ファイルが必要です。たとえば、次の XML を使用してメイン レイアウト ファイル res/layout/contacts_list_view.xml を作成できます。
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
この XML は、組み込みの Android ListView ウィジェット android:id/list を使用します。
次の XML を使用して、アイテム レイアウト ファイル contacts_list_item.xml を定義します。
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"/>
この XML は、組み込みの Android TextView ウィジェット android:text1 を使用します。
注: このレッスンでは、ユーザーから検索文字列を取得するための UI については説明しません。文字列を間接的に取得したい場合があるためです。たとえば、受信したテキスト メッセージの文字列と名前が一致する連絡先を検索するオプションをユーザーに提供できます。
作成した 2 つのレイアウト ファイルは、ListView を表示するユーザー インターフェースを定義します。次のステップでは、この UI を使用して連絡先リストを表示するコードを記述します。
連絡先のリストを表示するフラグメントを定義する
連絡先のリストを表示するには、まず Activity によって読み込まれる Fragment を定義します。Fragment を使用する方が柔軟な手法です。1 つの Fragment を使用してリストを表示し、2 つ目の Fragment を使用して、ユーザーがリストから選択した連絡先の詳細を表示できるためです。この方法を使用すると、このレッスンで紹介する手法の 1 つと、
連絡先の詳細を取得するレッスンで紹介する手法の 1 つを組み合わせることができます。
Activity から 1 つ以上の Fragment オブジェクトを使用する方法については、トレーニング クラス
フラグメントを使用して動的 UI を作成するをご覧ください。
連絡先プロバイダに対するクエリの作成を支援するため、Android フレームワークには ContactsContract というコントラクト クラスが用意されています。このクラスは、プロバイダにアクセスするための便利な定数とメソッドを定義します。このクラスを使用すると、コンテンツ URI、テーブル名、列に独自の定数を定義する必要がなくなります。このクラスを使用するには、次のステートメントを含めます。
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
このコードでは、CursorLoader を使用してプロバイダからデータを取得するため、ローダ インターフェース LoaderManager.LoaderCallbacks を実装するように指定する必要があります。また、ユーザーが検索結果のリストから選択した連絡先を検出できるように、アダプター インターフェース AdapterView.OnItemClickListener を実装します。次に例を示します。
Kotlin
... import android.support.v4.app.Fragment import android.support.v4.app.LoaderManager import android.widget.AdapterView ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Java
... import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.widget.AdapterView; ... public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
グローバル変数を定義する
コードの他の部分で使用されるグローバル変数を定義します。
Kotlin
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private val FROM_COLUMNS: Array<String> = arrayOf( if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY } else { ContactsContract.Contacts.DISPLAY_NAME } ) /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private val TO_IDS: IntArray = intArrayOf(android.R.id.text1) ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { ... // Define global mutable variables // Define a ListView object lateinit var contactsList: ListView // Define variables for the contact the user selects // The contact's _ID value var contactId: Long = 0 // The contact's LOOKUP_KEY var contactKey: String? = null // A content URI for the selected contact var contactUri: Uri? = null // An adapter that binds the result Cursor to the ListView private val cursorAdapter: SimpleCursorAdapter? = null
Java
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private final static String[] FROM_COLUMNS = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME }; /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private final static int[] TO_IDS = { android.R.id.text1 }; // Define global mutable variables // Define a ListView object ListView contactsList; // Define variables for the contact the user selects // The contact's _ID value long contactId; // The contact's LOOKUP_KEY String contactKey; // A content URI for the selected contact Uri contactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter cursorAdapter; ...
注: Contacts.DISPLAY_NAME_PRIMARY には Android 3.0(API バージョン 11)以降が必要なため、アプリの minSdkVersion を 10 以下に設定すると、Android Studio で Android Lint 警告が生成されます。この警告をオフにするには、FROM_COLUMNS の定義の前にアノテーション @SuppressLint("InlinedApi") を追加します。
フラグメントを初期化する
Fragment を初期化します。Android システムに必要な空の public コンストラクタを追加し、コールバック メソッド onCreateView() で Fragment オブジェクトの UI をインフレートします。次に例を示します。
Kotlin
// A UI Fragment must inflate its View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false) }
Java
// Empty public constructor, required by the system public ContactsFragment() {} // A UI Fragment must inflate its View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false); }
ListView の CursorAdapter を設定する
検索結果を ListView にバインドする SimpleCursorAdapter を設定します。連絡先を表示する ListView オブジェクトを取得するには、Fragment の親アクティビティを使用して Activity.findViewById() を呼び出す必要があります。setAdapter() を呼び出すときは、親アクティビティの Context を使用します。次に例を示します。
Kotlin
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) ... // Gets the ListView from the View list of the parent activity activity?.also { contactsList = it.findViewById<ListView>(R.id.contact_list_view) // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView contactsList.adapter = cursorAdapter } }
Java
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity contactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView contactsList.setAdapter(cursorAdapter); }
選択した連絡先リスナーを設定する
検索結果を表示する場合、通常は、ユーザーが 1 つの連絡先を選択して、さらに処理できるようにします。たとえば、ユーザーが連絡先をクリックしたときに、その連絡先の住所を地図上に表示できます。この機能を提供するには、まず、連絡先のリストを表示するフラグメントを定義するセクションで説明したように、クラスが AdapterView.OnItemClickListener を実装することを指定して、現在の Fragment をクリック リスナーとして定義します。
リスナーの設定を続行するには、onActivityCreated() の setOnItemClickListener() メソッドを呼び出して、リスナーを ListView にバインドします。次に例を示します。
Kotlin
fun onActivityCreated(savedInstanceState:Bundle) { ... // Set the item click listener to be the current fragment. contactsList.onItemClickListener = this ... }
Java
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. contactsList.setOnItemClickListener(this); ... }
現在の Fragment が ListView の OnItemClickListener であることを指定したので、クリック イベントを処理する必須メソッド onItemClick() を実装する必要があります。これについては、以降のセクションで説明します。
プロジェクションを定義する
クエリから返す列を含む定数を定義します。ListView の各アイテムには、連絡先の名前の主な形式を含む連絡先の表示名が表示されます。Android 3.0(API バージョン 11)以降では、この列の名前は Contacts.DISPLAY_NAME_PRIMARY です。それ以前のバージョンでは、名前は Contacts.DISPLAY_NAME です。
列 Contacts._ID は、SimpleCursorAdapter バインディング プロセスで使用されます。Contacts._ID と LOOKUP_KEY は、ユーザーが選択した連絡先のコンテンツ URI を作成するために一緒に使用されます。
Kotlin
... @SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Contacts.DISPLAY_NAME_PRIMARY else ContactsContract.Contacts.DISPLAY_NAME )
Java
... @SuppressLint("InlinedApi") private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME };
Cursor 列のインデックスの定数を定義する
Cursor の個々の列からデータを取得するには、Cursor 内の列のインデックスが必要です。Cursor 列のインデックスは、プロジェクション内の列名の順序と同じであるため、インデックスの定数を定義できます。次に例を示します。
Kotlin
// The column index for the _ID column private const val CONTACT_ID_INDEX: Int = 0 // The column index for the CONTACT_KEY column private const val CONTACT_KEY_INDEX: Int = 1
Java
// The column index for the _ID column private static final int CONTACT_ID_INDEX = 0; // The column index for the CONTACT_KEY column private static final int CONTACT_KEY_INDEX = 1;
選択基準を指定する
必要なデータを指定するには、検索するデータ列と検索する値をプロバイダに指示するテキスト式と変数の組み合わせを作成します。
テキスト表現には、検索列をリストする定数を定義します。この式には値を含めることもできますが、値は「?」プレースホルダで表すことをおすすめします。取得時に、プレースホルダは配列の値に置き換えられます。プレースホルダとして「?」を使用すると、検索仕様が SQL コンパイルではなくバインディングによって生成されます。この方法により、悪意のある SQL インジェクションの可能性を排除できます。次に例を示します。
Kotlin
// Defines the text expression @SuppressLint("InlinedApi") private val SELECTION: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?" else "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?" ... // Defines a variable for the search string private val searchString: String = ... // Defines the array to hold values that replace the ? private val selectionArgs = arrayOf<String>(searchString)
Java
// Defines the text expression @SuppressLint("InlinedApi") private static final String SELECTION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" : Contacts.DISPLAY_NAME + " LIKE ?"; // Defines a variable for the search string private String searchString; // Defines the array to hold values that replace the ? private String[] selectionArgs = { searchString };
onItemClick() メソッドを定義する
前のセクションで、ListView のアイテムクリック リスナーを設定しました。
次に、メソッド AdapterView.OnItemClickListener.onItemClick() を定義して、リスナーのアクションを実装します。
Kotlin
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) { // Get the Cursor val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply { // Move to the selected contact moveToPosition(position) // Get the _ID value contactId = getLong(CONTACT_ID_INDEX) // Get the selected LOOKUP KEY contactKey = getString(CONTACT_KEY_INDEX) // Create the contact's content Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey) /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ } }
Java
@Override public void onItemClick( AdapterView<?> parent, View item, int position, long rowID) { // Get the Cursor Cursor cursor = parent.getAdapter().getCursor(); // Move to the selected contact cursor.moveToPosition(position); // Get the _ID value contactId = cursor.getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY contactKey = cursor.getString(CONTACT_KEY_INDEX); // Create the contact's content Uri contactUri = Contacts.getLookupUri(contactId, mContactKey); /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ }
ローダを初期化する
CursorLoader を使用してデータを取得しているため、バックグラウンド スレッドと非同期取得を制御する他の変数を初期化する必要があります。次の例に示すように、onCreate() で初期化を行います。
Kotlin
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { // Always call the super method first super.onCreate(savedInstanceState) ... // Initializes the loader loaderManager.initLoader(0, null, this)
Java
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onCreate(Bundle savedInstanceState) { // Always call the super method first super.onCreate(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
onCreateLoader() を実装する
onCreateLoader() メソッドを実装します。このメソッドは、initLoader() を呼び出した直後にローダー フレームワークによって呼び出されます。
onCreateLoader() で、検索文字列パターンを設定します。文字列をパターンにするには、0 個以上の文字のシーケンスを表す「%」(パーセント)文字、または単一の文字を表す「_」(アンダースコア)文字、またはその両方を挿入します。たとえば、パターン「%Jefferson%」は「Thomas Jefferson」と「Jefferson Davis」の両方に一致します。
メソッドから新しい CursorLoader を返します。コンテンツ URI には Contacts.CONTENT_URI を使用します。次の例に示すように、この URI はテーブル全体を参照します。
Kotlin
... override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%$mSearchString%" // Starts the query return activity?.let { return CursorLoader( it, ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%" + searchString + "%"; // Starts the query return new CursorLoader( getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
onLoadFinished() と onLoaderReset() を実装する
onLoadFinished() メソッドを実装します。連絡先プロバイダがクエリの結果を返すと、ローダ フレームワークは onLoadFinished() を呼び出します。このメソッドで、結果 Cursor を SimpleCursorAdapter に入れます。これにより、検索結果で ListView が自動的に更新されます。
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter.swapCursor(cursor); }
ローダー フレームワークが結果 Cursor に古いデータが含まれていることを検出すると、メソッド onLoaderReset() が呼び出されます。既存の Cursor への SimpleCursorAdapter 参照を削除します。そうしないと、ローダ フレームワークが Cursor をリサイクルせず、メモリリークが発生します。次に例を示します。
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { // Delete the reference to the existing Cursor cursorAdapter?.swapCursor(null) }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor cursorAdapter.swapCursor(null); }
これで、検索文字列を連絡先の名前と照合し、結果を ListView で返すアプリの主要な部分が完成しました。ユーザーは連絡先の名前をクリックして選択できます。これによりリスナーがトリガーされ、連絡先のデータをさらに操作できます。たとえば、連絡先の詳細を取得できます。その方法については、次のレッスン連絡先の詳細を取得するをご覧ください。
検索ユーザー インターフェースの詳細については、API ガイドの検索インターフェースを作成するをご覧ください。
このレッスンの残りのセクションでは、連絡先プロバイダで連絡先を見つける他の方法について説明します。
特定の種類のデータで連絡先を照合する
この手法では、照合するデータの種類を指定できます。名前による取得は、このタイプのクエリの具体的な例ですが、連絡先に関連付けられている詳細データのタイプでも取得できます。たとえば、特定の郵便番号を持つ連絡先を取得できます。この場合、検索文字列は郵便番号の行に格納されているデータと一致する必要があります。
このタイプの取得を実装するには、まず前のセクションで説明した次のコードを実装します。
- プロバイダの読み取り権限をリクエストする。
- ListView とアイテムのレイアウトを定義します。
- 連絡先のリストを表示する Fragment を定義します。
- グローバル変数を定義します。
- Fragment を初期化します。
- ListView の CursorAdapter を設定します。
- 選択した連絡先リスナーを設定します。
-
Cursor 列インデックスの定数を定義します。
別のテーブルからデータを取得していますが、プロジェクション内の列の順序は同じであるため、Cursor に同じインデックスを使用できます。
- onItemClick() メソッドを定義します。
- ローダーを初期化します。
- onLoadFinished() と onLoaderReset() を実装します。
次の手順では、検索文字列を特定の種類の詳細データと照合して結果を表示するために必要な追加のコードを示します。
データの種類とテーブルを選択する
特定の種類の詳細データを検索するには、そのデータタイプのカスタム MIME タイプ値を知る必要があります。各データ型には、データ型に関連付けられた ContactsContract.CommonDataKinds のサブクラスの定数 CONTENT_ITEM_TYPE で定義された一意の MIME タイプ値があります。サブクラスの名前は、そのデータ型を示します。たとえば、メールデータのサブクラスは ContactsContract.CommonDataKinds.Email で、メールデータのカスタム MIME タイプは定数 Email.CONTENT_ITEM_TYPE で定義されます。
検索には ContactsContract.Data テーブルを使用します。射影、選択句、並べ替え順序に必要なすべての定数は、このテーブルで定義されるか、このテーブルから継承されます。
プロジェクションを定義する
プロジェクションを定義するには、ContactsContract.Data で定義されている列または継承元のクラスを 1 つ以上選択します。連絡先プロバイダは、行を返す前に、ContactsContract.Data と他のテーブルの間で暗黙的な結合を行います。次に例を示します。
Kotlin
@SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Data.DISPLAY_NAME_PRIMARY else ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY )
Java
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact };
検索条件を定義する
特定の種類のデータ内の文字列を検索するには、次のものから選択句を作成します。
-
検索文字列を含む列の名前。この名前はデータ型によって異なるため、データ型に対応する
ContactsContract.CommonDataKindsのサブクラスを見つけて、そのサブクラスから列名を選択する必要があります。たとえば、メールアドレスを検索するには、列Email.ADDRESSを使用します。 - 検索文字列自体。選択句の「?」文字として表されます。
-
カスタム MIME タイプの値を含む列の名前。この名前は常に
Data.MIMETYPEです。 -
データの種類のカスタム MIME タイプの値。前述のとおり、これは
ContactsContract.CommonDataKindsサブクラスの定数CONTENT_ITEM_TYPEです。たとえば、メールデータの MIME タイプ値はEmail.CONTENT_ITEM_TYPEです。定数の先頭と末尾に「'」(一重引用符)文字を連結して、値を一重引用符で囲みます。そうしないと、プロバイダは値を文字列値ではなく変数名として解釈します。この値にはプレースホルダを使用する必要はありません。ユーザーが指定した値ではなく定数を使用しているためです。
次に例を示します。
Kotlin
/* * Constructs search criteria from the search string * and email MIME type */ private val SELECTION: String = /* * Searches for an email address * that matches the search string */ "${Email.ADDRESS} LIKE ? AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
Java
/* * Constructs search criteria from the search string * and email MIME type */ private static final String SELECTION = /* * Searches for an email address * that matches the search string */ Email.ADDRESS + " LIKE ? " + "AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
次に、選択引数を含む変数を定義します。
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
onCreateLoader() を実装する
必要なデータとその検索方法を指定したら、onCreateLoader() の実装でクエリを定義します。このメソッドから、プロジェクション、選択テキスト式、選択配列を引数として使用して、新しい CursorLoader を返します。コンテンツ URI の場合は、Data.CONTENT_URI を使用します。次に例を示します。
Kotlin
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // OPTIONAL: Makes search string into pattern searchString = "%$mSearchString%" searchString?.also { // Puts the search string into the selection criteria selectionArgs[0] = it } // Starts the query return activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern searchString = "%" + searchString + "%"; // Puts the search string into the selection criteria selectionArgs[0] = searchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
これらのコード スニペットは、特定のタイプの詳細データに基づく基本的な逆引きの基礎となります。この方法は、アプリが特定の種類のデータ(メールなど)に重点を置いており、ユーザーがデータに関連付けられた名前を取得できるようにする場合に最適です。
すべての種類のデータで連絡先を照合する
任意のタイプのデータに基づいて連絡先を取得すると、名前、メールアドレス、住所、電話番号など、いずれかのデータが検索文字列と一致する連絡先が返されます。これにより、幅広い検索結果が得られます。たとえば、検索文字列が「Doe」の場合、任意のデータ型を検索すると、「John Doe」という連絡先が返されます。また、「Doe Street」に住んでいる連絡先も返されます。
このタイプの取得を実装するには、まず、前のセクションで説明した次のコードを実装します。
- プロバイダの読み取り権限をリクエストする。
- ListView とアイテムのレイアウトを定義します。
- 連絡先のリストを表示する Fragment を定義します。
- グローバル変数を定義します。
- Fragment を初期化します。
- ListView の CursorAdapter を設定します。
- 選択した連絡先リスナーを設定します。
- プロジェクションを定義します。
-
Cursor 列インデックスの定数を定義します。
このタイプの取得では、名前で連絡先を照合して結果を一覧表示するセクションで使用したのと同じテーブルを使用します。同じ列インデックスも使用します。
- onItemClick() メソッドを定義します。
- ローダーを初期化します。
- onLoadFinished() と onLoaderReset() を実装します。
次の手順では、検索文字列を任意のタイプのデータと照合して結果を表示するために必要な追加のコードを示します。
選択基準を削除する
SELECTION 定数または mSelectionArgs 変数を定義しないでください。
このタイプの検索では使用されません。
onCreateLoader() を実装する
onCreateLoader() メソッドを実装し、新しい CursorLoader を返します。連絡先プロバイダが自動的に検索文字列をパターンに変換するため、検索文字列をパターンに変換する必要はありません。ベース URI として Contacts.CONTENT_FILTER_URI を使用し、Uri.withAppendedPath() を呼び出して検索文字列を追加します。この URI を使用すると、次の例に示すように、任意のデータタイプの検索が自動的にトリガーされます。
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ val contentUri: Uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(searchString) ) // Starts the query return activity?.let { CursorLoader( it, contentUri, PROJECTION2, null, null, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ Uri contentUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, Uri.encode(searchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
これらのコード スニペットは、連絡先プロバイダの広範な検索を行うアプリの基盤となります。この手法は、連絡先アプリの連絡先リスト画面と同様の機能を実装するアプリに役立ちます。