全体表示

[ リスト ]

Toast、ちょいとメッセージ表示するのに便利ですね
で、ちょいちょいと利用していたのですが、今回面白いことになったのでメモとして残しておきます。

-☆-

Toast をメインスレッド(UIスレッド)で使う分には全く問題ありません。

が。

別にスレッド作って、そこで時間かかる処理とかを非同期でさせておいて、終わったら教えてくれろ、とToastで終了メッセージなんか出そうとすると、
A/dalvikvm(19512): Exception!!! threadid=9: thread exiting with uncaught exception (group=0x4001d858)
E/AndroidRuntime(19512): FATAL EXCEPTION: VeryVeryLongTimeProcess
E/AndroidRuntime(19512): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime(19512): 	at android.os.Handler.<init>(Handler.java:121)
                 :
                 :
                 :
なんて例外はいて死にます。ワオ。

しかしこのエラーはちょっと前にスコップですくって一山10円で売るくらい沢山眺めたエラーですよ!
と、ちょっと前にガッツリとAndroid 特有のスレッド作法(Looperのことな)やってなかったら、また涙で枕を濡らすところでした。

-☆-

解決策
こんな感じでLooper 回せばオワリ。

public void run() {
  // Toast表示用にLooper を回す
  Looper.myLooper().prepare();
  // なんかのスレッド処理
  doThreadProcess();
  // 無事Toastで表示できる
  Toast.makeText( context,"Done process.",Toast.LENGTH_SHORT).show();
  // Looper 回す
  Looper.myLooper.loop();
  // Looper終了
  Looper.myLooper.quit();
 }
こんな感じ。とにかく、Toastが使っているHandler を作成できればいいのです。

-☆-

どういうことかというと、Toastのソースでは、Toastクラスが持っているメンバTN内で
  final Handler mHandler = new Handler();    
と、Handler を引数無しでnew しています。引数無しでHandler を生成すると、Current Thread のハンドラを生成します。
普段つかうUIスレッドは気にせずともLooper が回されているので、UIスレッド上で引数なしnew しても問題なくハンドラが生成できますが、自前でスレッドを作成している場合は明示的に処置してやらないとLooperが回っていないので、そういうスレッド内でToastを生成すると、Current Thread(=自前スレッド)のハンドラを生成しようとしてこける、というカラクリです。
よって、Toast用にLooper を回してやれば、無事ハンドラが取得できて…ということです。

スレッドとハンドラとLooper については、結構ややこしいですけど押さえておくと楽ですよ。

-☆-

とまあこんな事でした。
一応ToastもUIに入るから、別スレッドから触らせないようにこういう思想なんでしょうけど、別スレッドで使えると大層便利なので…。まあイリーガルな手法ではあるので、何か不具合があるかもしれませんが。

この記事に

閉じる コメント(0)

コメント投稿

顔アイコン

顔アイコン・表示画像の選択

名前パスワードブログ
絵文字
×
  • オリジナル
  • SoftBank1
  • SoftBank2
  • SoftBank3
  • SoftBank4
  • docomo1
  • docomo2
  • au1
  • au2
  • au3
  • au4
投稿

開く トラックバック(0)


.


みんなの更新記事