金田著「はじめてのandroidプログラミング 第5版」を使って、勉強しています。
「第9章カウントダウンタイマーを作ろう」で使っているkotlinの文法のテクニックを解析してみます。
スコープ関数のrun関数を関数式に直してみます。
はじめはrun関数の意味が分からなかったので、まずはrun関数を使わず、インスタンスを作り、そのメソッド()を一行1行、操作する古いやり方に書き換えようとしました。しかしSoundPoolクラスのコンストラクタが非推奨になっていたので、本書のとおりSoundPool.Builder()でインスタンスを作ることにしました。調べて行く過程でrun関数を使わずに、ピリオドでメソッドを連結できることが分かったので紹介します。
以下、本書を持っている前提で説明します。本書を使って勉強中の方、一緒に勉強しましょう。
##0.前提
p253まで写経が済んでいるとします。
##1.原型
p253まで写経が済んでいる状態のコードを示します。説明に不要な部分は、著作権に配慮して省略しています。
本書のやり方では、SoundPool.Builder()のrun()関数の中に、AudioAttributesのインスタンスを作り出すAudioAttributes.Builderが含まれています。
class MainActivity : AppCompatActivity() {
// 省略
override fun onResume() {
super.onResume()
soundPool =
SoundPool.Builder().run {
val audioAttributes = AudioAttributes.Builder().run {
this.setUsage(AudioAttributes.USAGE_ALARM)
this.build()
}
this.setMaxStreams(1)
this.setAudioAttributes(audioAttributes)
this.build()
}
// 省略
}
// 省略
}
##2.AudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出す
先ずは、SoundPool.Builder()のrun関数の中に含まれているAudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出します。なおrun関数の動作については、本書p127に書かれています。
class MainActivity : AppCompatActivity() {
// 省略
override fun onResume() {
super.onResume()
val audioAttributes = AudioAttributes.Builder().run { // (2)(1)をここへ移動する。(追記)
this.setUsage(AudioAttributes.USAGE_ALARM) // this.は省略可
this.build()
}
soundPool = SoundPool.Builder().run {
// val audioAttributes = AudioAttributes.Builder().run { // (1)この部分を外に出す(削除)
// this.setUsage(AudioAttributes.USAGE_ALARM)
// this.build()
// }
this.setMaxStreams(1)
this.setAudioAttributes(audioAttributes)
this.build()
}
// 省略
}
}
ここで、 AudioAttributesクラスやSoundPoolクラスのインスタンスを作るのに、コンストラクタを用いることが非推奨であるから、AudioAttributes()やSoundPool()といった風にコンストラクタを使えないので、このままAudioAttributes.Builder()、SoundPool.Builder()を使ってインスタンスを作ることとした。
##3.ピリオドで連結する方法に変換する
上記のコードをピリオドでメソッドを連結した形式に書き換えます。ピリオドで連結する形式に変換するにあたり、nyan のアプリ開発を参考にした。
// 省略
override fun onResume() {
super.onResume()
// 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
val audioAttributes = AudioAttributes.Builder() // run()関数とthisを外し、関数をピリオド(.)連結する。
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
// val audioAttributes = AudioAttributes.Builder().run {
// this.setUsage(AudioAttributes.USAGE_ALARM)
// this.build()
// }
// 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
soundPool = SoundPool.Builder() // run()関数とthisを外し、関数をピリオド(.)連結する。
.setMaxStreams(1)
.setAudioAttributes(audioAttributes)
.build()
// soundPool = SoundPool.Builder().run {
// this.setMaxStreams(1)
// this.setAudioAttributes(audioAttributes)
// this.build()
// }
// 省略
}
// 省略
ピリオドで連結する形が使えるのは、AudioAttributes.BuilderクラスやSoundPool.Builderクラスのメソッドの戻り値が、AudioAttributes.Builder型やSoundPool.Builder型であるからである。例えばAudioAttributes.BuilderクラスのメソッドsetUsage()は、戻り値の型がAudioAttributes.Builderである。setUsage()のリファレンスを参照して頂きたい。
さて、第2項のrun()関数を使うやり方と第3項のピリオドで連結するやり方とでは、どちらが見やすいでしょうか?私は、電車ごっこのような、順繰りとタスクが進むピリオドで連結する方が、分かりやすく見やすいと思います。run関数を使うか、関数式を使うかの選択は、趣味の問題でしょうか?疑問が残ります。
##4.ピリオド連結を分解し、メソッドを一行一行処理する(2021/01/21追記)
当初やり方が分からなかったが、落ち着いて考えたら方法を思いついたので記述する。
ピリオドで連結していたメソッドを分解し、一行一行に変数を設けるようにコードを書き換える。
// val audioAttributes = AudioAttributes.Builder()
// .setUsage(AudioAttributes.USAGE_ALARM)
// .build()
val buildedAudioAttributes = AudioAttributes.Builder()
val setUsagedAudioAttributes = buildedAudioAttributes.setUsage(AudioAttributes.USAGE_ALARM)
val audioAttributes = setUsagedAudioAttributes.build()
// soundPool = SoundPool.Builder()
// .setMaxStreams(1)
// .setAudioAttributes(audioAttributes)
// .build()
val buildedSoundPool = SoundPool.Builder()
val setMaxStreamsedSoundPool = buildedSoundPool.setMaxStreams(1)
val setAudioAttributedBuildedSoundPool = setMaxStreamsedSoundPool.setAudioAttributes(audioAttributes)
soundPool = setAudioAttributedBuildedSoundPool.build()
// 省略
##5.蛇足
見た目、汚らしいですがrun()関数の中で、メソッドを連結することも出来るみたいです。第2項、第3項と比較してください。
【例1】
soundPool = SoundPool.Builder().run {
setMaxStreams(1)
.setAudioAttributes(audioAttributes) // ここから先を関数式で連結
.build()
}
【例2】
soundPool = SoundPool.Builder().run {
setMaxStreams(1)
setAudioAttributes(audioAttributes)
.build() // これだけを関数式で連結
}