このレッスンでは、検索文字列の全部または一部にデータが一致する連絡先のリストを取得する方法を示します。使用する手法は以下のとおりです。
- 連絡先の名前を照合する
- 検索文字列を連絡先の名前データの全部または一部と照合して、連絡先のリストを取得します。連絡先プロバイダでは重複する名前での登録が許可されているため、一致する名前が複数返されることもあり得ます。
- 特定の種類のデータ(電話番号など)を照合する
- 検索文字列を特定の種類の詳細データ(メールアドレスなど)と照合して、連絡先のリストを取得します。たとえば、メールアドレスが検索文字列と一致するすべての連絡先を一覧表示できます。
- すべての種類のデータを照合する
- 検索文字列を名前、電話番号、住所、メールアドレスなどの任意のタイプの詳細データと照合して、連絡先のリストを取得します。たとえば、検索文字列に任意の型のデータを受け入れ、データが文字列に一致する連絡先を一覧表示できます。
注: このレッスンのすべての例では、CursorLoader
を使用して連絡先プロバイダからデータを取得します。CursorLoader
は、UI スレッドとは別のスレッドでクエリを実行します。そのため、クエリの負荷で UI の応答時間が遅くなって、ユーザー エクスペリエンスが低下する、ということはありません。詳しくは、Android トレーニング クラスの
バックグラウンドでのデータの読み込みをご覧ください。
プロバイダの読み取り権限をリクエストする
連絡先プロバイダでなんらかの種類の検索を行うには、アプリに READ_CONTACTS
権限が必要です。この権限をリクエストするには、<uses-permission>
要素を <manifest>
の子要素としてマニフェスト ファイルに追加します。
<uses-permission android:name="android.permission.READ_CONTACTS" />
連絡先を名前で照合して結果を一覧表示する
この手法では、検索文字列を、連絡先プロバイダの ContactsContract.Contacts
テーブル内にある連絡先の名前と照合します。通常は、結果を ListView
に表示して、ユーザーが一致した連絡先から選択できるようにします。
ListView とアイテム レイアウトを定義する
検索結果を ListView
に表示するには、ListView
を含む UI 全体を定義するメイン レイアウト ファイルと、1 行の ListView
を定義するアイテム レイアウト ファイルが必要です。たとえば、次の 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
を使用して、ユーザーがリストから選択した連絡先の詳細を表示するためです。この方法を使用すると、このレッスンで紹介した手法と、
連絡先の詳細を取得するで紹介した手法を組み合わせることができます。
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 警告が生成されます。この警告をオフにするには、アノテーション @SuppressLint("InlinedApi")
を FROM_COLUMNS
の定義の前に追加します。
フラグメントを初期化する
Fragment
を初期化します。Android システムに必要な空のパブリック コンストラクタを追加し、コールバック メソッド 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()
で検索文字列のパターンを設定します。文字列をパターンにするには、ゼロ個以上の一連の文字を表す「%(パーセント)」記号と、単一の文字を表す「_(アンダースコア)」記号のいずれかまたは両方を挿入します。たとえば、パターン「%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); }
onLoaderReset()
メソッドは、結果の Cursor
に古いデータが含まれていることをローダ フレームワークが検出したときに呼び出されます。既存の 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 とアイテム レイアウトを定義します。
- 連絡先のリストを表示するフラグメントを定義する。
- グローバル変数を定義します。
- フラグメントを初期化する。
- ListView の CursorAdapter を設定します。
- 選択した連絡先リスナーを設定する。
-
Cursor 列のインデックスの定数を定義します。
別のテーブルからデータを取得しても、プロジェクションの列の順序は同じであるため、Cursor に同じインデックスを使用できます。
- onItemClick() メソッドを定義します。
- ローダを初期化します。
- onLoadFinished() と onLoaderReset() を実装する。
次の手順では、検索文字列を特定の種類の詳細データと照合して結果を表示するために必要な追加のコードを示します。
データの種類とテーブルを選択する
特定の種類の詳細データを検索するには、そのデータ型のカスタム MIME タイプの値を確認する必要があります。データの種類ごとに、一意の MIME タイプの値があります。この値は、データの種類に関連付けられている ContactsContract.CommonDataKinds
のサブクラスにある定数 CONTENT_ITEM_TYPE
で定義されます。サブクラスにはデータの種類を示す名前が付けられています。たとえば、メールデータのサブクラスは 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 とアイテム レイアウトを定義します。
- 連絡先のリストを表示するフラグメントを定義する。
- グローバル変数を定義します。
- フラグメントを初期化する。
- ListView の CursorAdapter を設定します。
- 選択した連絡先リスナーを設定する。
- プロジェクションを定義します。
-
Cursor 列のインデックスの定数を定義します。
このタイプの取得では、連絡先を名前で照合して結果を一覧表示するで使用したのと同じテーブルを使用します。同じ列のインデックスも使用します。
- onItemClick() メソッドを定義します。
- ローダを初期化します。
- onLoadFinished() と onLoaderReset() を実装する。
次の手順では、検索文字列を任意のタイプのデータと照合して結果を表示するために必要な追加のコードを示します。
選択基準を削除する
SELECTION
定数や mSelectionArgs
変数は定義しないでください。これらは、このタイプの取得では使用されません。
onCreateLoader() を実装する
onCreateLoader()
メソッドを実装して、新しい CursorLoader
を返します。検索文字列は連絡先プロバイダによって自動的に変換されるため、パターンに変換する必要はありません。Contacts.CONTENT_FILTER_URI
をベース 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 ); }
これらのコード スニペットは、連絡先プロバイダの広範な検索を行うアプリに基づいています。 この手法は、アプリ People の連絡先リスト画面に似た機能を実装するアプリで役立ちます。