AndroidJava/トーストをたくさん作る

無駄にトーストを、大量に作ってみたくなる(2019-04-14)


Toastっていうのは、何かアプリで作業したタイミングで
スマホとかの下のところに
「コピーしました」とか、保存しましたとか、もうだめですとか、
小さくポップアップさせるアレです。

今回の課題としては以下の2つです。

  • UIスレッドで呼ぶ必要がある
  • ボタン連打時の対応(cancelの実装)

トーストが連打される事態を許容するのかどうかは、また別として...
さておき、
まず、通常はこうで良いと思います。

Toast.makeText(getApplicationContext(), "とーすと!", Toast.LENGTH_LONG).show();

このToastですが、
UIスレッドで実行しないとExceptionになります。
出力例としてはこんなログ?

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

UIスレッドって単語を初めて聞いた方はWeb検索して頂くとして...

...ふわっと説明すると、
ユーザインタフェースなスレッド「ではない」やつというのは、
(例えば AsyncTaskやら doInBackground やらを使って、)
Webからダウンロードしたり、大きいファイルを読み込んだりを
メインとは別のスレッドを呼んで(バックグラウンドで)行う場合があります。
そういった処理の中でToastを呼んだりすると上記のExceptionが発生します。
というか、
処理が複雑に、ソースコードが大きくなってきた時に
「これはUIか、否か...もうムリじゃよ〜」とかなっちゃった時に、
後述する runOnUiThread() で実行しちゃえば良いんじゃね?という雑な対応のお話です。


あともう1つの問題は、
トーストの「おかわり」が連続で発生する場合です。
おそらく最初の一枚しか画面表示されない、
あるいは大量のトーストがいつまでたっても終わらないと思います。
(私が試した手元の端末で、Android 8 で前者、4.2 で後者になったような気がします...)
それを避けるために、表示中のものをcancel() した上で追加のトーストを表示したい。

それらを踏まえた例が以下

 private Toast toast; // 変数として前回分を保持する
 void setToast2UI(String toast_message) {
     if(toast != null) toast.cancel(); // 前回分があれば消す。
 
     // この呼び元が worker thread の場合は UI thread へ渡す
     runOnUiThread(new Runnable() {
         String toast_message2;
 
         Runnable setToast(String str) {
             toast_message2 = str;
             return this;
         }
 
         @Override
         public void run() { // Toast を呼ぶ
             toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_LONG);
             toast.setText(toast_message2);
             toast.show();
         }
     }.setToast(toast_message)); // setToast 経由で toast_message を渡す
 }

runOnUiThread でUIスレッドへ処理を渡しています。

Threadに自分で欲しい任意の引数を渡す(今回はtoast_message)
というのを初めて見た方に補足すると、
ここを仲介して「無名クラスに変数を渡す」みたいなことをやっています。
setToast部分は自作の関数で名前はてきとーです。

別案として、「toast = new Toast(context);」のように一回宣言して
同じ1つのインスタンスを使いまわそうとしたのですが、
そうすると、cancel() 直後の次のtoast.show() もキャンセル扱いされてしまったので
上記のように、その都度あたらしいトーストを上書きする形にしました。

さぁ、思う存分トーストを作るぞ [smile]