Android Jetpack の Paging を用いたリストを再読み込みするまでの長かった道のり

# やりたいこと

[PagedListAdapter](https://developer.android.com/reference/android/arch/paging/PagedListAdapter) をセットした [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView) を再度読み込みし直したい。

## シチュエーション

例：[Material Design > Backdrop](https://material.io/design/components/backdrop.html) スタイルの検索結果一覧画面にて

* 「検索ワード」が変更されたり「絞り込みの条件」が追加された場合に検索結果一覧をリロードしたい
* 検索結果一覧が Swipe-to-Refresh された場合

など。

![backdrop-shrine-ahero.png](https://qiita-image-store.s3.amazonaws.com/0/6881/20307f10-db34-0538-54a9-bfae387e73fb.png)

## 試み

[PagedListAdapter](https://developer.android.com/reference/android/arch/paging/PagedListAdapter) を再生成して [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView) にセットし直すというようなチャチな発想では全然ダメでした :no_good:

# 参考

公式の [googlesamples/android-architecture-components/PagingWithNetworkSample/](https://github.com/googlesamples/android-architecture-components/tree/master/PagingWithNetworkSample) を解読します。

![Screenshot_1530550075.png](https://qiita-image-store.s3.amazonaws.com/0/6881/8532deed-4378-149e-dc3e-3b2764a214da.png)

天才・Googler 様が考える実装はクセがスゴかったです。

## 仕組み

### 「検索ワード」や「絞り込みの条件」が変化した場合

[ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) が保持する検索条件に関する [MutableLiveData](https://developer.android.com/reference/android/arch/lifecycle/MutableLiveData) の値を更新して [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView) をリフレッシュしています。

### Swipe-to-Refresh した場合

ネットワーク上からデータを取得していれば [DataSource.invalidate()](https://developer.android.com/reference/android/arch/paging/DataSource#invalidate) を呼び、[Room](https://developer.android.com/topic/libraries/architecture/room) からデータを取得していればネットワーク上からデータを取り直しトランザクション終了後自動的に反映されます。

# 実践

2018 年 7 月 8 日時点の[公式のサンプル](https://github.com/googlesamples/android-architecture-components/tree/master/PagingWithNetworkSample)は「検索ワード」のみが [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView) をリフレッシュするトリガーになっていますが、「検索ワード」と「絞り込みの条件」が変化した場合に検索結果一覧をリロードする方法について考えてみました。

## サンプル

1. 複数ある検索条件を１つにまとめたデータクラス `SearchParameter` を定義
2. [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) で `SearchParameter` の [MutableLiveData](https://developer.android.com/reference/android/arch/lifecycle/MutableLiveData) を保持
3. 検索条件が変化して検索結果一覧を更新したい場合は [MutableLiveData.setValue()](https://developer.android.com/reference/android/arch/lifecycle/MutableLiveData#setvalue) を実施します

``` SearchParameter.kt
/**
 * 複数の検索条件をまとめたデータクラス
 */
data class SearchParameter(
        var keyword: String?, // キーワード
        var minPrice: Int?,   // 価格の下限
        var maxPrice: Int?,   // 価格の上限
        var size: Int?        // 大きさ
)
```

``` SearchViewModel.kt
class SearchViewModel(private val repository: SearchRepository) : ViewModel() {

    private val searchParameterMutableLiveData = MutableLiveData<SearchParameter>()

    private val repoResult = map(searchParameterMutableLiveData) { searchParameter ->
        repository.search(searchParameter = searchParameter, pageSize = 20)
    }

    val searchResults = switchMap(repoResult) { it.pagedList }!!

    /**
     * 条件を指定して検索を実施
     */
    fun search(keyword: String?, minPrice: Int?, maxPrice: Int?, size: Int?) {
        searchParameterMutableLiveData.value = SearchParameter(
                keyword = keyword,
                minPrice = minPrice,
                maxPrice = maxPrice,
                size = size)
    }
}
```