Android
Kotlin
websocket
zaif
Dagger2
AndroidDay 25

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

はじめに

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

Group.png

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

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

躓きポイント① Java時代にお世話になってたButterKnifeが必要ない!

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

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"
        >

/ 省略 /
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関係ありません!w
完全に自分の経験不足のものです。Kotlinを勉強しながらAndroidアプリでのWebSocketの使い方も調べて行きました。実際にやってみたところ、Okhttpで簡単に実装できました!w

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の都合上チャートは難しそう。
頑張りますかね〜。