Activity#runOnUiThread
Activity#runOnUiThreadの実装がこちら。
1 2 3 4 5 6 7 | public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } } |
内部的にHandler#postしていますね。
ここでちょっと気になるのが
1 | Thread.currentThread() != mUiThread |
そしてUIスレッドである場合は
1 | action.run(); |
どんな時問題になるか
runOnUiThreadをHandler#postと同じモノだと考えて利用しているとハマる可能性があります。
まぁ多分大丈夫と思いますが以下のhello2()様な実行順に依存性があるような実装をしちゃうとヤバイですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Handler mHandler = new Handler(); String mMessage = "hello!" ; private void hello(){ mHandler.post( new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), mMessage, Toast.LENGTH_SHORT).show(); } }); mMessage = "good bye!" ; } private void hello2(){ runOnUiThread( new Runnable(){ @Override public void run() { Toast.makeText(getApplicationContext(), mMessage, Toast.LENGTH_SHORT).show(); } }); mMessage = "good bye!" ; } |
別スレッドからhello(),hello2()、UIスレッドからhello(),hello2()を実行するとToastに何が表示されるでしょうか?
呼び出しパターン | 結果 |
---|---|
別スレッドからHandler#postを呼ぶ(hello()) | "good bye!"が表示される |
UIスレッドからHandler#postを呼ぶ(hello()) | "good bye!"が表示される |
別スレッドからrunOnUiThreadを呼ぶ(hello2()) | "good bye!"が表示される |
UIスレッドからrunOnUiThreadを呼ぶ(hello2()) | "hello!"が表示される |
なんか一個動きが違うのがいるーーーーー。
はいそういう事ですね。
結論
色々省略しますが
・Handler#post, runOnUiThreadに渡すRunnableが触る変数にはHandler#post, runOnUiThread呼び出し後触らない。
・Handler#post, runOnUiThreadはなるべくメソッドの最後に呼ぶ
・Handler#post, runOnUiThreadに渡すRunnableの中では呼び出し元のメンバ変数などを触らない。
Handler#post, runOnUiThreadを呼び出すメソッド内でfinalな変数を宣言しておいてそれにアクセスしたりする様にする。
とかやってるといいんじゃないでしょかー
追記
実際hello(), hello2()のmMessage = "good bye!";の直前にThread.sleep(1000);を追加して実行してみるとどうなるか実験してみました。
結果は以下です
なんか一個動きが違うのがいるーーーーー。
はいそういう事ですね。
以下の様な事になります。
結論は変わらず。
どちらにせよHandler#post, runOnUiThreadを呼び出した後にHandler#post, runOnUiThread内部で利用されうる値などの書き換えはやばいよ、という事ですね。
結果は以下です
呼び出しパターン | 結果 |
---|---|
別スレッドからHandler#postを呼ぶ(hello()) | "hello!"が表示される |
UIスレッドからHandler#postを呼ぶ(hello()) | "hello!"が表示される |
別スレッドからrunOnUiThreadを呼ぶ(hello2()) | "good bye!"が表示される |
UIスレッドからrunOnUiThreadを呼ぶ(hello2()) | "hello!"が表示される |
なんか一個動きが違うのがいるーーーーー。
はいそういう事ですね。
以下の様な事になります。
呼び出しパターン | 動き |
---|---|
別スレッドからHandler#postを呼ぶ(hello()) | 呼び出し後の処理とRunnableの実行どちらが先かは判らない |
UIスレッドからHandler#postを呼ぶ(hello()) | 必ず呼び出し後の処理が実行された後にRunnableが実行される |
別スレッドからrunOnUiThreadを呼ぶ(hello2()) | 呼び出し後の処理とRunnableの実行どちらが先かは判らない |
UIスレッドからrunOnUiThreadを呼ぶ(hello2()) | 必ずRunnableが実行された後に呼び出し後の処理が実行される |
結論は変わらず。
どちらにせよHandler#post, runOnUiThreadを呼び出した後にHandler#post, runOnUiThread内部で利用されうる値などの書き換えはやばいよ、という事ですね。
0 件のコメント:
コメントを投稿