🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

3回答

2159閲覧

ボタンを点滅させる方法を教えて下さい

K.TAKASHI.1

総合スコア14

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2019/10/04 21:04

以前、ボタンを点滅させたいと質問したところ、タイマーを使うと良いと回答していただき、次のように

onCreate に以下のようにコードを書きました。

Timer().schedule(500, 500) {
timer ++

val x = timer%2 when(x){ 1-> button2.visibility = View.INVISIBLE 0-> button2.visibility = View.VISIBLE } }

変数timerの初期値は0で、アプリ起動と同時に数字を足していく。
定数xに0と1が交互に入る
1のときはbuttom2が非表示
0のときはbuttom2が表示

と考えてコードを書きましたがうまくいきません。

INVISIBLEはできるのですが、VISIBLEのときにアプリが落ちてしまいます。
なぜでしょうか?ご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

INVISIBLEはできるのですが、VISIBLEのときにアプリが落ちてしまいます。
なぜでしょうか?ご教授お願いいたします。

なぜアプリが落ちるのか?の直接の答えとしては、「実行してはいけないタイミングでButton#visibilityを書き換えているためにExceptionが発生し、それをハンドリングしていないから」です。Exceptionをcatch するようにすれば、どんな種類の例外(エラー)が発生しているか分かります。質問者さんのコードとおおむね同じ例で示すと以下のようになります。

Kotlin

1val button2: Button = findViewById(R.id.button2) 2Timer().schedule(500, 500) { 3 try { 4 // 簡単に、ボタンの表示状態でトグル 5 if (button2.visibility == View.VISIBLE) { 6 button2.visibility = View.INVISIBLE 7 } else { 8 button2.visibility = View.VISIBLE 9 } 10 } catch (ex: Exception) { 11 Log.w("TestApp", "EXCEPTION: " + ex.message) 12 } 13}

これは、以下のようなメッセージがlogcatに出力されます。

2019-10-05 11:30:18.049 10517-10555/com.example.myapp1 W/TestApp: EXCEPTION: Only the original thread that created a view hierarchy can touch its views.

では何がいけないのか?という疑問の答えとしては、既に他回答でいただいたように、ボタンが張り付いている画面の処理を担当しているUIスレッドの(少し語弊がある表現ですが)持ち物であるのみが、描画関連処理を正しく完遂できるボタンに、別のスレッドであるタイマー用のスレッドからButton#visibilityを書き換えている、と言う行為です。INVISIBLEにしてもOKだったのは、ラッキーだった程度のことで、これも本来はやってはいけません。ButtonTextViewなどのUIの部品は、基本的にUIスレッドから触る必要があります。

そんな場合は、UIスレッド内でHandlerクラスオブジェクトを生成し、postメソッドを用いてUIスレッド内で処理を行うようにします。(ここでは述べませんが、他の方法もあります)

Kotlin

1// UIスレッドでHandlerを生成(大事!) 2val handler = Handler() 3Timer().schedule(500, 500) { 4 handler.run { 5 post { 6 if (button2.visibility == View.VISIBLE) { 7 button2.visibility = View.INVISIBLE 8 } else { 9 button2.visibility = View.VISIBLE 10 } 11 } 12 } 13}

隠れている問題
Timerを使用してタイマースレッドを起動すると、そのスレッドはUIスレッドとは別に生存し続けます。例えばAndroidの「ホーム」や「戻る」ボタンを押して、アプリの画面が終了したように見えてもタイマースレッドは動作し続けています。(Android Studioのデバッガーで確認してみてください)画面の終了などの適切なタイミングに合わせ、停止させる必要があります。ただ、本質問とは別のトピックだと思いましたので、詳細は省かせてもらいます。


余談
「他スレッドからUIを更新する」と言うプログラミング上の話題/問題は、Androidに限らず、またteratailに限らずかなり「あるある」です。Androidプログラミングでの対処の仕方は昔からほぼ定型でたくさん存在しますが、サンプルコードとして圧倒的にJavaのコードが多く、そのJavaのコードからKotlinに転化するのは、特にAndroidプログラミングの初心者さんからすると壁かなぁ、と個人的に思います。(Kotlin初心者の私自身も、結構悩みます)

投稿2019/10/05 03:17

編集2019/10/05 03:29
dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

コルーチンを用いれば、UIスレッド云々を気にせずにループを回せるんじゃないかという解として。

app/build.gradle
(dependenciesの中に1行追加)

gradle

1dependencies { 2 3 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1" 4 5}

MainActivity.kt

kotlin

1class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() { 2 3 override fun onCreate(savedInstanceState: Bundle?) { 4 super.onCreate(savedInstanceState) 5 setContentView(R.layout.activity_main) 6 7 launch { 8 while(true) { 9 delay(500) 10 if (button2.visibility == View.VISIBLE) { 11 button2.visibility = View.INVISIBLE 12 } else { 13 button2.visibility = View.VISIBLE 14 } 15 } 16 } 17 } 18 19 override fun onDestroy() { 20 super.onDestroy() 21 cancel() 22 } 23} 24

こんな形でも目的の動作にはなると思います。

投稿2019/10/05 16:07

keicha_hrs

総合スコア6768

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

kotlinのことはよくわからないですが、一般的なフォームアプリケーションでは、UIコンポーネントに関わる操作はUIスレッド上で実行しなければならない、ということがあります

もしかして、そのタイマハンドラは別スレッドになってるんじゃないでしょうか

コルーチンによるUIプログラミングガイド (日本語訳)

投稿2019/10/04 22:25

y_waiwai

総合スコア88040

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問