Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

Ringtoneでカウントダウンタイマー終了時に音でお知らせ!

 どうも!LSSです!

 

 KotlinでAndroidアプリ開発を練習中です。

 

 今回は、前回作成した簡易カウントダウンタイマー&ストップウォッチカウントダウンが終わってもリアクションが無いという最大の欠陥解決します!

 

 

今回の肝!

 Ringtoneを使うにあたって必要な記載です。

 

UriとRingtoneを、Activity直下で宣言

lateinit var ur0:Uri
lateinit var rt0:Ringtone

 

UriとRingtoneを、onCreate内で設定

ur0=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
rt0=RingtoneManager.getRingtone(this,ur0)

 

Ringtoneを鳴らす。鳴らしたいところに記載

rt0.play()

 

Ringtoneを止める。止めたいところとonDestroy内に記載

rt0.stop()

 

 用意が2行×2回 必要ですが、「鳴らす・止める」はとってもシンプルな記載ですね^^

 

もうひとつの肝!

  実機で動作テストしていたところ、
「画面を縦から横に変えると画面がリセットされ、タイマーもリセットされる」
という新たな重大な欠陥が発覚しましたwww

 画面を固定するか、向きを変えても動作を継続するようにするか、前者を選択。

 画面を固定するのはManifestに書くか、Kotlinコードに書くか、後者を選択しました。 

 

画面を縦に固定する指示を、onCreate内に記載

requestedOrientation =ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

 

 

コード全文

Ringtone関連赤文字にしています。

それ以外にも色々、前回からいじっています。

また、ur0rt0は任意の名前(好きに変えちゃってOKな部分)です。

 


package jp.littlestrangesoftware.mytech

import android.content.pm.ActivityInfo
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.view.View
import kotlinx.android.synthetic.main.activity_timer.*
import java.util.*

class timerActivity : AppCompatActivity() {

var cld0=Calendar.getInstance() // 計測開始時の時刻値 保管用
var cld1=Calendar.getInstance() // 現在の時刻値 保管用
var tflag=false // タイマー動作中はtrueになるフラグ
var cntF=true // カウントダウン未終了フラグ

var CntT=180 // カウントダウン用の時間を秒で指定

lateinit var ur0:Uri // Uriを宣言
lateinit var rt0:Ringtone
// Ringtoneを宣言

val hnd0=Handler() // Handlerを作成
val rnb0=object:Runnable{
override fun run() {
cld1.timeInMillis=System.currentTimeMillis() // 現在の時刻値をミリ秒で取得

var i=CntT+((cld0.timeInMillis-cld1.timeInMillis)/1000).toInt() // 残り秒数

// カウントダウンが完了している場合
if (i<0) {
i = 0

// カウントダウン終了後に1回だけ行う
if (cntF){
cntover() // 処理内容を書いた別のfunを呼び出す
cntF=false // フラグをfalseにする事で連続動作を防止
}
}
// カウントダウンタイマーの表示
tvCntD.text="%02d:%02d".format(i/60,i%60)

// ストップウォッチの表示
tv0.text="%.2f".format((cld1.timeInMillis-cld0.timeInMillis).toFloat()/1000)

hnd0.postDelayed(this,10) // 0.01秒後にこの処理を再度呼び出し
}
}

// カウントダウン終了後に行う処理
fun cntover(){
rt0.play() // Ringtone(音)を鳴らす
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_timer)
requestedOrientation =ActivityInfo.SCREEN_ORIENTATION_PORTRAIT // 縦画面に固定

ur0=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM) // uriを設定
rt0=RingtoneManager.getRingtone(this,ur0)
// Ringtoneを設定

}


// START・STOPボタンを押した時の処理
fun btSclk(v:View){
if (tflag) { // tflagはタイマー作動中はtrue、停止中はfalse

// 作動中にSTOPが押された場合の処理
tflag=false
btS.text="START"
rt0.stop() // Ringtone(音)を止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル

}else{

// 停止中にSTARTが押された時の処理
tflag=true
btS.text="STOP"
cntF=true


cld0.timeInMillis=System.currentTimeMillis() //STARTが押された時の時刻値をcld0にセット
hnd0.post(rnb0) // handlerタイマー処理を開始

}
}

override fun onDestroy() {
rt0.stop() // Ringtone(音)を停止
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル
super.onDestroy()
}

}

 

 

 

このタイマー、意外と使える事にびっくり

 実機でテストしていた時に気づいたんですが、かなり単純に作ったこのタイマー、「おおっ!」となった点がありました。 

 

その1!
タイマー作動開始後に、スマホの電源ボタンを押して画面オフ・ロック状態になっても、時間が来ると鳴ってくれます!
ロック解除すると、ロック中も正しく動作していた事が確認できます。動作しないと思ってた。

 

その2!
タイマー作動開始後に、別アプリ(そこそこ重めのスマホゲー)を起動して遊んでいても、時間が来ると鳴ってくれます!動作しないと思ってた。

※よほどメモリを圧迫するような処理があると、Activityが破棄される=画面を縦横切り替えた時と同じ事が起こるとは思われますが、そうでない程度の別アプリ動作は大丈夫なようです。

 

 

意外と苦労した…

  完成形こそ、2行×2、1行×2の計6行ですが、たどり着くまでに紆余曲折がありました^^;

 まず、Ringtoneにしようとする前にToneGeneratorで鳴らしてみようとしたのですが、まぁまぁすんなり作れた代わりに音があまりに味気ないのでボツにしましたw

 

 Ringtoneならスマホのアラーム音をそのまま使えるようなので、そっちに書きなおし。

 ネットでRingtoneの使い方を検索すると、大抵、鳴らすだけなら準備部分を2行で済ませているので、Activity直下にてUriRingtoneを設定して走らせてみました。

が、コンパイル・インストールはされるものの、エラーでアプリが落ちるw

 

 後ろから徐々にコメントアウトして突きとめたのは、

val rt0=RingtoneManager.getRingtone(this,ur0)

って記載がActivity直下だとマズい様子。
this、の部分がいまだよく理解していない「context」で、
 ここを何度もapplicationContextにしたりthisにしたりも繰り返しましたw

 

 結局のところ、Activity直下だったのが問題で、onCreate内であればようやく動作しました。
で、playstopは別々に動作させたいため、lateinit varでActivity直下で宣言だけ行い、onCreate内で設定するようにし、見た目的・分かりやすさ的にUriも同じ扱いとしました。

 

 

 

 

残る課題

 前回も書いた、

 

  • カウントダウン終了時に音と振動でお知らせ(のうちの振動部分)
  • タイマー動作中にAndroid側の機能で勝手に終わってしまわないようにする
  •  ストップウォッチにLAP計測機能をつける

 の他に、ストップウォッチとして使ってる時にカウントダウンが終了して音が鳴ったら、ストップウォッチを止めずに音だけ止める手段を用意する必要がありますね。

 

 また、

↑これが好きでちょくちょく食べてますが、これは5分待ちなので、 やっぱり
カウントダウンの時間は設定可能にしておくべきですなw

 

 

てなところで、今回はここまで!

次回もまた、よろしくお願いします^^

 

 

AndroidStudio+Kotlin記事インデックス