Android Kotlin基礎講座 08.3:フィルタリングとインターネットデータの詳細ビュー
目次
タスク:結果をフィルタリングする
現在アプリは全ての火星物件を概要ページのグリッドに表示しています。もしユーザーが貸し出し用の物件を探している場合、物件が販売用であることを示すドルアイコンは役には立ちますが、それでもページ内にはスクロールするには多すぎる物件があります。
このタスクでは、概要フラグメントにオプションメニューを追加して、ユーザーが貸し出し用のみ、または販売用のみ、または全てを表示できるようにします。
このタスクを達成する方法の一つは概要ページにあるそれぞれのMarsPropertyをテストし、合致した物件のみを表示するという方法です。しかしながら、実際のMarsウェブサービスにはrentタイプかbuyタイプかで取得する物件を制御することができるクエリパラメータやfilterというオプションがあります。このフィルタークエリを以下の用にブラウザ内でrealestateウェブサービスのURLにつけて使うことができます。
https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buy
このタスクでは、MarsApiServiceクラスを修正し、Retrofitを用いてウェブサービスリクエストにクエリオプションを追加します。その後クエリオプションを使って全ての火星物件データを再ダウンロードできるようにオプションメニューを実装します。これでウェブサービスから取得した結果には興味のある物件しか含まれていないので、概要ページのグリッド用のビュー表示ロジックは一切変更する必要がありません。
ステップ1:Mars APIサービスをアップデートする
リクエストを変更するためには、このレッスンの最初の記事で実装したMarsApiServiceを変更する必要があります。フィルタリングAPIを提供するように修正していきます。
- network/MarsApiService.ktを開いてください。インポート文のすぐ下に、ウェブサービスが期待しているクエリ値と合致する定数を定義するためにMarsApiFilterというenumを作成してください。
enum class MarsApiFilter(val value: String) {
SHOW_RENT("rent"),
SHOW_BUY("buy"),
SHOW_ALL("all") }
- getProperties()メソッドを修正し、以下のようにフィルタークエリ用のstringを取るようにし、@Query(“filter”)でアノテーションしてください。
要求されたら、retrofit2.http.Queryをインポートしてください。
@QueryアノテーションはgetProperties()メソッド(とRetrofit)にフィルターオプションを使ってウェブサービスリクエストを作るように伝える役割をしています。getProperties()が呼び出される度に、リクエストURLには?filter=typeという部分が含まれ、これによってウェブサービスからクエリに合致する結果のみが返ってくるようになります。
suspend fun getProperties(@Query("filter") type: String): List<MarsProperty>
ステップ2:OverviewViewModelをアップデートする
アプリはOverviewViewModelのgetMarsRealEstateProperties()メソッド内のMarsApiServiceからデータをリクエストします。そのリクエストがフィルター引数を取るようにアップデートする必要があります。
- overview/OverviewViewModel.ktを開いてください。前のステップで行った変更によるAndroid Studioのエラーが発生しているかと思います。getMarsRealEstateProperties()の呼び出しのパラメーターとして、MarsApiFilter(予期されるフィルター値のenum)を追加してください。
要求されたら、com.example.android.marsrealestate.network.MarsApiFilterをインポートしてください。
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
- Retrofitサービス中のgetProperties()の呼び出しを変更してstringでフィルタークエリを渡すように変更してください。
_properties.value = MarsApi.retrofitService.getProperties(filter.value)
- init{}ブロック内でgetMarsRealEstateProperties()の引数として、MarsApiFilter.SHOW_ALLを渡して、アプリが最初に読み込む際には全ての物件を表示できるようにしてください。
init {
getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
- クラスの最後に、MarsApiFilterを引数にとるupdateFilter()メソッドを追加し、その引数を使ってgetMarsRealEstateProperties()を呼び出してください。
fun updateFilter(filter: MarsApiFilter) {
getMarsRealEstateProperties(filter)
}
ステップ3:オプションメニューにフラグメントを接続させる
最後のステップはオーバーフローメニューをフラグメントに繋げて、ユーザーがメニューのオプションを選択したときに、ビューモデルのupdateFilter()を呼び出すようにすることです。
- res/menu/overflow_menu.xmlを開いてください。MarsRealEstateアプリは全ての物件を表示する、貸し出し用のみを表示する、販売用のみを表示するという三つのオプションを提供しているオーバーフローメニューを既に持っています。
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/show_all_menu"
android:title="@string/show_all" />
<item
android:id="@+id/show_rent_menu"
android:title="@string/show_rent" />
<item
android:id="@+id/show_buy_menu"
android:title="@string/show_buy" />
</menu>
- overview/OverviewFragment.ktを開いてください。クラスの最後で、メニューのアイテムが選択されたときに処理するためのonOptionsItemSelected()メソッドを実装してください。
override fun onOptionsItemSelected(item: MenuItem): Boolean {
}
- onOptionsItemSelected()内で、適切なフィルターを用いてビューモデル上でupdateFilter()メソッドを呼び出してください。オプション間で処理を切り替えるためにはKotlinのwhen{}ブロックを使います。
デフォルトのフィルター値にはMarsApiFilter.SHOW_ALLを使います。メニューアイテムを処理したのでtrueを返してください。
要求されたら、MarsApiFilter(com.example.android.marsrealestate.network.MarsApiFIlter)をインポートしてください。完成したonOptionsItemSelected()メソッドは以下のようになります。
override fun onOptionsItemSelected(item: MenuItem): Boolean {
viewModel.updateFilter(
when (item.itemId) {
R.id.show_rent_menu -> MarsApiFilter.SHOW_RENT
R.id.show_buy_menu -> MarsApiFilter.SHOW_BUY
else -> MarsApiFilter.SHOW_ALL
}
)
return true
}
- コンパイルしてアプリを起動してください。アプリは最初に販売用の物件にはドルアイコンを表示させながら、全てのタイプの物件をグリッドで表示します。
- オプションメニューからRentを選択してください。物件が再読み込みされ、ドルアイコンがついたもんが表示されなくなります。(貸し出し用物件のみが表示されている)
フィルターされた物件のみを表示するために画面がリフレッシュされる間、少し待つ必要がある場合があります。 - オプションメニューからBuyを選択してください。物件がまた再読み込みされ、全てドルアイコンがついている物件が表示されます。(販売用の物件のみが表示されている)