RxAndroidでSwipeRefreshLayoutを使う

- ListViewを使うときによくあるアクションとして下に引っ張って更新するPull to Refreshというような動きがありますが、AndroidではSupport LibraryからSwipeRefreshLayoutというものが提供されています。今回はこれをRxAndroidと一緒に使ってみました。
- 今、Kotlinでアプリを書いているので、サンプルのコードもKotlinになっていますがJavaで適時置き換えてください。
- 事前の準備は [KotlinでRxAndroid1.0を使う](http://qiita.com/rei-m/items/6a5cbebe7cb6fe679cac) を参照。

# RxSwipeRefreshLayout
- RxAndroidからは`RxSwipeRefreshLayout`というBinding用のクラスが提供されています。

```kotlin
// refreshingはRefreshLayoutのプログレスを切り替えることができるAction1を返す
val refreshLayoutRefreshing = RxSwipeRefreshLayout.refreshing(refreshLayout)

// refreshesはProgress状態になったら配信されるObservable<void>を返す
val refreshLayoutStream = RxSwipeRefreshLayout.refreshes(refreshLayout)
```

# 試してみる
### LayoutにSwipeRefreshLayoutを追加
- SwipeRefreshLayoutでListViewを囲みます。

```xml
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/list_event"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.SwipeRefreshLayout>
```

### Activityに実装
- サンプルとしてAtndのAPIを叩いてイベント情報をObservableで返すというものを作っています。下に引っ張ったらプログレスが表示されて次ページ分が読み込まれるというサンプルになっています。

```kotlin
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        val view = inflater.inflate(R.layout.fragment_item, container, false)

        // ListViewにAdaptorとリスナをセット
        mListView = view.findViewById(R.id.list_event) as AbsListView
        mListView?.adapter = mAdapter
        mListView?.onItemClickListener = this

        // Observerを作成
        val observer = Observers.create<AtndApi.Companion.Entity>(
                { t ->
                    // onNext
                    mAdapter?.add(t.title)
                    mAdapter?.notifyDataSetChanged()
                },
                { e ->
                    // onError
                    println("Error!! ${e.message}")
                },
                {
                    // onComplete
                    mAdapter?.notifyDataSetChanged()
                })

        // Observableを作成
        // 配信時は新しいスレッド
        // 監視者はメインスレッド
        val observable = AtndApi.request(mWordForSearch, 1)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())

        val refreshLayout = view.findViewById(R.id.refresh) as SwipeRefreshLayout

        // ローディング中のプログレスの色を設定
        refreshLayout.setColorSchemeColors(Color.RED, Color.GREEN, Color.BLUE)
        refreshLayout.setProgressBackgroundColorSchemeColor(Color.LTGRAY)

        val refreshLayoutRefreshing = RxSwipeRefreshLayout.refreshing(refreshLayout)
        val refreshLayoutStream = RxSwipeRefreshLayout.refreshes(refreshLayout)

        // 購読を開始

        // 初回のAPIコール
        mSubscriptions.add(observable.subscribe(observer))

        // RefreshLayoutを監視
        mSubscriptions.add(refreshLayoutStream.subscribe({

            // ローディングが始まったらAPIコール
            val subscription = AtndApi.request(mWordForSearch, mAdapter?.count!! + 1)
                    .subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .finallyDo({
                        // 読み込みが終わったらRefreshLayoutのローディング状態を解除
                        refreshLayoutRefreshing.call(false)
                    })
                    .subscribe(observer)

            mSubscriptions.add(subscription)
        }))

        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()

        // 購読を解除する
        mSubscriptions.unsubscribe()
    }
```

- プログレスはこんな感じで表示されます。

<img width="497" alt="スクリーンショット 2015-11-28 10.15.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/25841/1f8ac2d6-0aa4-72db-4821-ee116d974895.png">

- コードはこちらに https://github.com/rei-m/kotlin_sample