Zaif公式Androidアプリが微妙だったのでKotlinの勉強を兼ねて通貨ペアViewerアプリを作った

# はじめに
なんだかんだで体調を崩してしまい、2018年1月は仕事をお休みしてました。
がそろそろ、リハビリ兼ねてKotlinの勉強をしようと考え、Zaifの仮想通貨ペアViewerアプリを作りました（題材をZaifにしたのは公式アプリがお粗末なでｋ・・・ゲフンゲフン）。こんなやつ↓

![Group.png](https://qiita-image-store.s3.amazonaws.com/0/106116/5c5757b1-c555-7b6c-a6f8-d04762ae5ab0.png)

左の一覧ページの方は１０秒毎（ZaifAPIはリクエスト数に制限があり、かつ、一括で終値を取得できないのでこんな仕様にorz）に終値をとってきていて、個別ページの方はWebSocketでリアルタイムに更新しています。今回はKotlinで作った上でJavaとの相違点、躓きそうなポイントをまとめてみました。

お急ぎの方はGitHubにコードを公開しているので下記からどうぞ
https://github.com/tarumzu/ZaifClientAndroid

# 躓きポイント① Java時代にお世話になってたButterKnifeが必要ない！
多くの方々がお世話になったであろうButterKnifeですが、必要ありません！！
というのは言い過ぎですが、バインドしてあげなくともKotlin Android ExtensionsというKotlin標準の機能で直接Layoutの要素を取得することが出来ます。こんな感じ。

```xml:activity_main.xml
/ 省略 /

    <android.support.v4.widget.SwipeRefreshLayout
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:id="@+id/swiperefresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

/ 省略 /
```

```kotlin:MainActivity.kt

import kotlinx.android.synthetic.main.activity_main.*

/ 省略 /

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // xmlで定義したIDで取ってこれる！
        swiperefresh.setOnRefreshListener({
            Timber.d("onRefresh called from SwipeRefreshLayout");
            initiateRefresh();
        });

/ 省略 /
```

ただ、ViewHolderなど特定の変数に紐付けたい場合があったり、イベントのバインドは出来ないという不便さもあるのも事実。そういった場合はKotlin用のKotterKnifeを使うのも手です。
https://github.com/JakeWharton/kotterknife

# 躓きポイント② WebSocket！
これはKotlin関係ありません！ｗ
完全に自分の経験不足のものです。Kotlinを勉強しながらAndroidアプリでのWebSocketの使い方も調べて行きました。実際にやってみたところ、Okhttpで簡単に実装できました！ｗ

```kotlin:DetailActivity.kt
/ 省略 /
        private inner class EchoWebSocketListener : WebSocketListener() {

            override fun onOpen(webSocket: WebSocket, response: Response) {
                Timber.d("open")
            }

            override fun onMessage(webSocket: WebSocket?, text: String?) {
                Timber.d("Receiving : " + text!!)
                var currencyPairStream = mGson.fromJson(text, CurrencyPairStream::class.java)

                activity.runOnUiThread({
                    price.text = if (currencyPairStream.lastPrice != null) {
                        currencyPairStream.lastPrice!!.price.toString()
                    } else {
                        currencyPairStream.price.toString()
                    }
                })
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                Timber.d("Receiving bytes : " + bytes.hex())
            }

            override fun onClosing(webSocket: WebSocket?, code: Int, reason: String?) {
                webSocket!!.close(1000, null)
                Timber.d("Closing : $code / $reason")
            }

            override fun onFailure(webSocket: WebSocket?, t: Throwable?, response: Response?) {
                Timber.d("Error : " + t?.message)
            }

        }
/ 省略 /

            val request: Request = Request.Builder().url(getString(R.string.api_ws_base_url, mCurrencyPair)).build()
            mWebSocket = mZaifClientWSOkHttpClient.newWebSocket(request, EchoWebSocketListener())

            // TODO: 調べた感じ不要な気がする。詳しい人教えて下さいm(_ _)m
            //mZaifClientWSOkHttpClient.dispatcher().executorService().shutdown()

```


# 躓きポイント③ KotlinとJavaの構文のちがい
当然のごとく多くの方が躓いており、偉大な先人様の記事が大変参考になりました。個人的に一番戸惑ったのはnullの扱いですかね〜。Javaとは異なり、KotlinはデフォルトでNullを許しません。（?つかったり?:つかえばNullも扱えますが、そこは賛否両論あるところ…）
https://qiita.com/koher/items/bcc58c01c6ff2ece658f

# 最後に
まだまだこのアプリを使いやすくしたいな〜と考えてます。買い板、売り板表示させたり、実際に売買出来るようにしたり。APIの都合上チャートは難しそう。
頑張りますかね〜。