[メモ]Bottom Navigation ActivityのKotlinボイラープレートをリファクタリング

Bottom Navigation Activity を自動生成すると、こんな感じのソースが生成される。

Kotlin 初学者のため勘所を外していたら申し訳ないのだけれど、僕個人の趣味にあわせて書き換えてみたい。

```kotlin
class HomeActivity : AppCompatActivity() {

    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_home -> {
                message.setText(R.string.title_home)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_dashboard -> {
                message.setText(R.string.title_dashboard)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_notifications -> {
                message.setText(R.string.title_notifications)
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }

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

        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
    }
}
```

# イベントリスナーの持ち上げ

`OnNavigationItemSelectedListener` が `private val` として、初期化と同時に構築され変更不能なフィールドとして確保されていることは好感が持てる。
ところでアクティビティを想定すると、ナビゲーションは一つ。（二つ以上のナビゲーションが画面内に存在するのは、 UI として下品だろう）

つまりリスナーを独立させる必要はなく、このアクティビティが唯一持つナビゲーションのリスナーであればよい。

```kotlin
class HomeActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {

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

        navigation.setOnNavigationItemSelectedListener(this)
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.navigation_home -> {
                message.setText(R.string.title_home)
                return true
            }
            R.id.navigation_dashboard -> {
                message.setText(R.string.title_dashboard)
                return true
            }
            R.id.navigation_notifications -> {
                message.setText(R.string.title_notifications)
                return true
            }
        }
        return false
    }
}
```

# テキスト設定のくくりだし
さて。 `onNavigationItemSelected` は内側の `when` の各 `case` がほとんど同じ構造であることに気づく。

こういう場合はくくりだしだ。

```kotlin
    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        var resId: Int?
        when (item.itemId) {
            R.id.navigation_home -> resId = R.string.title_home
            R.id.navigation_dashboard -> resId = R.string.title_dashboard
            R.id.navigation_notifications -> resId = R.string.title_notifications
            else -> resId = null
        }
        resId?.let {
            message.setText(resId)
            return true
        }
        return false
    }
```

そして `when` を関数としてくくり出すことで、さらに整理できる。

```kotlin

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        return stringIdFrom(item.itemId)?.let {
            message.setText(it)
            true
        } ?: false
    }

    private fun stringIdFrom(itemId: Int): Int? {
        return when (itemId) {
            R.id.navigation_home -> R.string.title_home
            R.id.navigation_dashboard -> R.string.title_dashboard
            R.id.navigation_notifications -> R.string.title_notifications
            else -> null
        }
    }
```

# 整理し終えたコード

掲げるまでもないけれど、全体はこう変わる。

```kotlin
class HomeActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {

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

        navigation.setOnNavigationItemSelectedListener(this)
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        return stringIdFrom(item.itemId)?.let {
            message.setText(it)
            true
        } ?: false
    }

    private fun stringIdFrom(itemId: Int): Int? {
        return when (itemId) {
            R.id.navigation_home -> R.string.title_home
            R.id.navigation_dashboard -> R.string.title_dashboard
            R.id.navigation_notifications -> R.string.title_notifications
            else -> null
        }
    }
}
```

ネストの深さから見ても、スッキリしたのではないだろうか？

アプリケーションで繰り返し利用されるようならば `stringIdFrom` を共通で使う「関数オブジェクト」として切り出してもいいだろう。