はじめに (対象読者・この記事でわかること)

この記事は、Androidアプリ開発を学んでいる中級者〜上級者の方を対象としています。特にListViewを使いこなしたい方や、リストデータをフィルタリングしたい方に最適です。 この記事を読むことで、ListView内の複数項目から特定の条件に合う項目だけを抽出するJavaコードの実装方法がわかります。また、ArrayAdapterやFilterableインターフェースの使い方も理解できます。実際のアプリ開発でよくある「検索機能」や「カテゴリ別表示」の実装に役立つ知識を習得できます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Android Studioの基本的な操作 - Java言語の基礎知識 - Androidの基本的なUIコンポーネントの理解 - ListViewとArrayAdapterの基本的な使い方

ListViewフィルタリングの概要と背景

Androidアプリ開発において、ListViewは複数のデータをリスト形式で表示するための非常に便利なコンポーネントです。しかし、大量のデータをすべて表示するとユーザーが目的の情報を見つけにくくなることがあります。そのような場合、特定の条件に合う項目だけを抽出して表示することが求められます。

例えば、商品リストアプリではカテゴリ別に表示したり、連絡先アプリでは名前で検索したりする機能が必要です。この記事では、ListView内の複数項目から任意の項目だけを取り出す実装方法について解説します。具体的には、フィルタリング機能を実装し、ユーザーが入力したキーワードに基づいてリストを動的に更新する方法を取り上げます。

ListViewから特定の項目を抽出する具体的な実装方法

ステップ1: ListViewとArrayAdapterの基本設定

まずは、ListViewとArrayAdapterの基本的な設定から始めます。以下にサンプルコードを示します。

Java
// ListViewの取得 ListView listView = findViewById(R.id.listView); // リストデータの準備 List<String> items = new ArrayList<>(); items.add("りんご"); items.add("ばなな"); items.add("みかん"); items.add("いちご"); items.add("ぶどう"); // ArrayAdapterの作成と設定 ArrayAdapter<String> adapter = new ArrayAdapter<>( this, android.R.layout.simple_list_item_1, items ); // ListViewにアダプターを設定 listView.setAdapter(adapter);

このコードでは、単純な文字列のリストをArrayAdapterに設定し、ListViewに表示しています。

ステップ2: Filterableインターフェースの実装

次に、フィルタリング機能を実装します。ArrayAdapterはFilterableインターフェースを実装しているため、簡単にフィルタリング機能を追加できます。以下にフィルタリング機能を実装したArrayAdapterのサンプルコードを示します。

Java
public class CustomArrayAdapter extends ArrayAdapter<String> implements Filterable { private List<String> originalItems; private List<String> filteredItems; private Filter filter; public CustomArrayAdapter(Context context, List<String> items) { super(context, android.R.layout.simple_list_item_1, items); this.originalItems = new ArrayList<>(items); this.filteredItems = new ArrayList<>(items); } @Override public int getCount() { return filteredItems.size(); } @Override public String getItem(int position) { return filteredItems.get(position); } @Override public Filter getFilter() { if (filter == null) { filter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint == null || constraint.length() == 0) { // 検索条件がない場合はすべてのアイテムを表示 results.count = originalItems.size(); results.values = originalItems; } else { // 検索条件に一致するアイテムを抽出 List<String> filteredList = new ArrayList<>(); String filterString = constraint.toString().toLowerCase().trim(); for (String item : originalItems) { if (item.toLowerCase().contains(filterString)) { filteredList.add(item); } } results.count = filteredList.size(); results.values = filteredList; } return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { filteredItems = (List<String>) results.values; notifyDataSetChanged(); } }; } return filter; } }

このカスタムアダプターでは、Filterableインターフェースを実装し、フィルタリングロジックを追加しています。performFilteringメソッドでは、検索条件に一致するアイテムを抽出し、publishResultsメソッドでは、フィルタリング結果を反映してリストを更新しています。

ステップ3: 検索機能の実装

次に、検索機能を実装します。EditTextを追加し、入力された文字列に基づいてListViewをフィルタリングするようにします。以下にレイアウトファイルとActivityのサンプルコードを示します。

activity_main.xml:

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" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/searchEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="検索キーワードを入力" android:inputType="text" /> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>

MainActivity.java:

Java
public class MainActivity extends AppCompatActivity { private CustomArrayAdapter adapter; private ListView listView; private EditText searchEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Viewの取得 listView = findViewById(R.id.listView); searchEditText = findViewById(R.id.searchEditText); // リストデータの準備 List<String> items = new ArrayList<>(); items.add("りんご"); items.add("ばなな"); items.add("みかん"); items.add("いちご"); items.add("ぶどう"); items.add("メロン"); items.add("スイカ"); items.add("パイナップル"); items.add("キウイ"); items.add("オレンジ"); // カスタムアダプターの作成と設定 adapter = new CustomArrayAdapter(this, items); listView.setAdapter(adapter); // 検索テキスト変更時のリスナー設定 searchEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // 変更前の処理(何もしない) } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // 変更中の処理(何もしない) } @Override public void afterTextChanged(Editable s) { // 変更後の処理:フィルタリングを実行 adapter.getFilter().filter(s.toString()); } }); } }

このコードでは、EditTextにTextWatcherを設定し、テキストが変更されるたびにフィルタリングを実行しています。これにより、ユーザーが入力したキーワードに基づいてListViewが動的に更新されます。

ハマった点やエラー解決

フィルタリング機能を実装する際に、以下のような問題に遭遇しました。

問題1: フィルタリング後にリストが更新されない

フィルタリングを実行してもListViewが更新されない問題が発生しました。原因は、ArrayAdapterのgetFilter()メソッドを呼び出す際に、フィルタリング結果を反映するためのnotifyDataSetChanged()が呼び出されていなかったためです。

問題2: 大文字小文字を区別しないフィルタリングを実装したい

デフォルトのフィルタリングでは、大文字小文字が区別されてしまい、「りんご」と入力しても「リンゴ」がヒットしませんでした。

問題3: 複数の条件でフィルタリングしたい

単一のキーワードだけでなく、複数の条件でフィルタリングしたい場合がありました。例えば、カテゴリとキーワードの両方でフィルタリングしたい場合です。

解決策

上記の問題に対する解決策として、以下のポイントを押さえることが重要です。

問題1の解決策:

CustomArrayAdapterクラスでFilterableインターフェースを実装し、publishResultsメソッド内でnotifyDataSetChanged()を呼び出すことで、フィルタリング後にリストが更新されるようになりました。

問題2の解決策:

performFilteringメソッド内で、検索キーワードと各アイテムを小文字に変換してから比較することで、大文字小文字を区別しないフィルタリングを実装しました。

Java
String filterString = constraint.toString().toLowerCase().trim(); for (String item : originalItems) { if (item.toLowerCase().contains(filterString)) { filteredList.add(item); } }

問題3の解決策:

カスタムオブジェクトを作成し、複数のプロパティを持たせることで、複数の条件でフィルタリングを実装しました。以下にサンプルコードを示します。

Java
public class Fruit { private String name; private String category; public Fruit(String name, String category) { this.name = name; this.category = category; } public String getName() { return name; } public String getCategory() { return category; } } public class CustomArrayAdapter extends ArrayAdapter<Fruit> implements Filterable { // ...(前のコードと同様) @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint == null || constraint.length() == 0) { // 検索条件がない場合はすべてのアイテムを表示 results.count = originalItems.size(); results.values = originalItems; } else { // 検索条件に一致するアイテムを抽出 List<Fruit> filteredList = new ArrayList<>(); String filterString = constraint.toString().toLowerCase().trim(); for (Fruit fruit : originalItems) { if (fruit.getName().toLowerCase().contains(filterString) || fruit.getCategory().toLowerCase().contains(filterString)) { filteredList.add(fruit); } } results.count = filteredList.size(); results.values = filteredList; } return results; } // ...(他のコードは同様) }

このコードでは、Fruitクラスにnameとcategoryという2つのプロパティを持たせ、フィルタリングの条件として両方のプロパティを考慮しています。これにより、名前とカテゴリの両方でフィルタリングが可能になります。

まとめ

本記事では、ListView内の複数項目から任意の項目だけを取り出す方法について解説しました。Filterableインターフェースを実装したカスタムアダプターを作成し、EditTextと連携させることで、ユーザーが入力したキーワードに基づいてリストを動的にフィルタリングする方法を学びました。

  • ポイント1: Filterableインターフェースを実装することで、簡単にフィルタリング機能を追加できます。
  • ポイント2: 大文字小文字を区別しないフィルタリングを実装するには、比較対象の文字列を小文字に変換します。
  • ポイント3: 複数の条件でフィルタリングしたい場合は、カスタムオブジェクトを作成し、複数のプロパティを持たせます。
  • ポイント4: EditTextにTextWatcherを設定し、テキスト変更時にフィルタリングを実行することで、リアルタイムにリストを更新できます。

この記事を通して、ListViewのフィルタリング機能を実装する方法が理解できたかと思います。今後は、より高度なフィルタリング機能や、RecyclerViewを使った実装方法についても記事にする予定です。

参考資料