PR

Kotlinで停止したタイマを再開できない時の解決方法

Androidアプリ

タイマは動かせます、停止もできます、けど再開できません…

こうした悩みを解決します。

本記事を通じてできるようになること

・タイマ使用時にエラーがでないよう設計する
・タイマON/OFFをボタン制御で切り替える
・タイマタスクで直接メインアクティビティのUI要素にアクセスする
・テキストビューの値が数値だけか判別する

サンプルプログラムはこちら

ソースコードも提供しています
サンプルプログラムのソースコードを見る

長くなりました、ではいきましょう。

姫野秀徳

組み込みエンジニアとしてメーカー勤務10年。
第二種電工事士、基本情報技術者、Code.org認定教師。
microbitを用いた電子工作&プログラミング教室を開校。
組み込み開発の実際を発信するyoutube活動も行う。

無料で学べる組み込み開発オンラインスクールはじめました!
https://kumicla.tatepro.com

姫野秀徳をフォローする

結論:タイマは使う度に新たに作る必要がある

結論から先に言うと、タイマは使い捨てのスレッドです。

タイマは停止、再開という概念のものではなく、停止するときはタイマスレッドを破棄、再開したいときは新たに作り直しと考えます。

そのため、設計にあたってタイマ開始する直前にタイマオブジェクトを生成する必要があります。

こんな感じでタイマを開始させます。

 val timer = Timer() /*これが重要!*/
 timer.scheduleAtFixedRate(1000, 3000) {
     //do something
 }

一度だけタイマを実行するならつまずかないと思います。

開始したタイマを停止して再開したいときに問題が起こるんですね。

慌てずゆっくり読み進めて理解していきましょうね。

タイマ再開時にアプリが停止する問題

テキトーに関数作って引数のbool値でタイマの開始、停止を試みます。

この処理だと1回目はタイマが正常動作しますが、2回目のタイマ動作をしようとした瞬間にアプリが落ちます。

val timer = Timer()

fun timerstart(flag:Boolean){
    if(flag == true) {
        timer.scheduleAtFixedRate(1000, 3000) {
            //do something
        }
    } else {
        timer.cancel()
    }
}

動作を考える

まず事前に定義しているval timer = Timer()でタイマオブジェクトができました。

そしてtrueを引数として、timerstart関数をよんでタイマをスタートします。

上記は1秒のウェイトの後、3秒毎に処理を行うscheduleAtFixedRateメソッドを使っています。

タイマを止めるときはfalseを引数にtimerstart関数をよんでタイマが停止します。

ここまでは設計通りに動くはずです。

タイマ再開時に落ちる原因と対策

タイマは実は既存スレッドとは別のスレッドを作り、その中でタスクを実行しています。

なので、cancel()でタイマを停止するというのは、タイマスレッドを終了(=破棄)しているということになります。

タイマスレッドが終了して無くなっているのにタイマを再開しようとすると、タイマの実体がないのでアプリ側が処理できずに落ちてしまいます。

そのため、冒頭でも書きましたがタイマを開始する前にはタイマオブジェクトを作る必要があるのです。

タイマは再開するというより、タイマを作る→動かす→捨てる→タイマを作る→…を毎回繰り返していることになります。

val timer = Timer()

fun timerstart(flag:Boolean){
    if(flag == true) {
        timer = Timer() //作る
        timer.scheduleAtFixedRate(1000, 3000) { //動かす
            //do something
        }
    } else {
        timer.cancel() //捨てる
    }
}

タイマからUI要素にアクセスすると落ちる問題と対策

タイマは独自のスレッドを作って動くので、アクティビティやフラグメントのUI要素に直接アクセスすることはできません。

この問題を機に、タイマはスレッドだと気づく人もいるのでは。

UIを制御したい場合は、runOnUiThreadメソッドを用いる必要があります。

runOnUiThreadが分からない方はこちら

動作中のタイマの実行間隔は変更できない問題と対策

動作中のタイマの実行間隔に引数を参照させて、動作中に実行間隔を可変させることもできません。

いったんタイマを停止して、再度実行間隔を変えてから再度動かす必要があります。

val timer = Timer()
var temp = 10

fun timerstart(flag:Boolean){
    if(flag == true) {
        timer = Timer() //作る
        timer.scheduleAtFixedRate(1000, temp*1000) { //これはできない
            //do something
        }
    } else {
        timer.cancel() //捨てる
    }
}

サンプルプログラム提供中

タイマを用いてテキストビューの数値を1秒毎にインクリメントするプログラムを提供しています。

手っ取り早くタイマを動かしたいという方は下記からソースコードをダウンロードして使ってみてください。

サンプルプログラムのソースコードを見る

まとめ

タイマは使い捨てのスレッドです

タイマ開始直前にタイマオブジェクトを生成する必要があります(そうでないとアプリが落ちる)

この内容が良いと思ったら、いいね💖を押して教えてください!

組みクラ – 組み込み開発を学び、未来を創るエンジニアへ
無料で学べる!組み込み開発の基礎から応用までをマスターできるオンラインスクール「組みクラ」

組み込みエンジニアは、あらゆる産業の基盤を支える重要な職業です。
私たちタテプロは、次世代の組み込みエンジニアを育成し、業界の競争力を高めるために活動しています。
あなたも、無料で学べる「組みクラ」で、組み込み開発のスキルをしっかり身につけ、キャリアを加速させましょう!
今すぐ学び始めて、将来の自分をステップアップさせる第一歩を踏み出しませんか?

\立プロとLINEで友だちになりませんか/
立プロと友だちになる
Androidアプリ
シェアしていただけると嬉しいです!

コメント

タイトルとURLをコピーしました