web-dev-qa-db-ja.com

GUIの更新:ランナブルとメッセージ

他のスレッドからGUIを更新するには、基本的に2つの主要なアプローチがあります。

  1. 次のいずれかの方法でJava.lang.Runnableを使用します。

    Activity.runOnUiThread(Runnable)
    View.post(Runnable)
    View.postDelayed(Runnable, long)
    Handler.post(Runnable)
    
  2. Android.os.Messageを使用します。

    Handler.sendMessage(Message) / Handler.handleMessage(Message)
    

AsyncTaskを使用することもできますが、私の質問は、非常に単純なコンポーネントを更新するユースケースに焦点を当てています。両方のアプローチを使用してどのように行われるかを見てみましょう。

  1. Runnablesの使用:

    TextViev tv = ...;
    final String data = "hello";
    Runnable r = new Runnable() {
    
        @Override
        public void run(){
            tv.setText(data);
        }
    
    };
    //Now call Activity.runOnUiThread(r) or handler.post(r), ...
    
  2. メッセージの使用:

    Message m = handler.obtainMessage(UPDATE_TEXT_VIEW, "hello");
    handler.sendMessage(m);
    
    //Now on handler implementation:
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == UPDATE_TEXT_VIEW){
                String s = (String) msg.obj;
                tv.setText(data);
            } ... //other IFs?
        }
    

私見、メッセージは行く方法ではありません:理由:

  • Android以外の新しいプログラマーにとっては理解しにくい(ハンドラーは構築中にスレッドにフックします)。
  • メッセージがプロセスの境界を越える場合、オブジェクトのペイロードはパーセル可能である必要があります。
  • メッセージは再利用されます(適切にクリーンアップされていないとエラーが発生しやすくなりますか?)
  • ハンドラーには2つの役割があります(メッセージを送信するだけでなく、メッセージも処理します)
  • メッセージ属性は公開されていますが、ゲッター/セッターも提供します。

一方、Runnablesは、よく知られているコマンドパターンに従い、プログラマーにとって使いやすく、読みやすくなっています。

では、RunnableよりもMessagesを使用する利点は何ですか?現代のメッセージはバックグラウンドにプッシュされていますかAndroidプログラミング?Runnablesでは実行できないメッセージで実行できることはありますか?

前もって感謝します。

47
Mister Smith

MessageRunnableの使用にはほとんど違いがないと思います。それは主に個人的な好みに要約されます。どうして?ソースコードを見ると、Runnableの投稿はまったく同じメッセージングメカニズムを使用していることがわかります。 RunnableMessageにアタッチし、それを送信するだけです。

4.4.2ソースコード

public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

参照: Grepコード-ハンドラー

20
Jay Soyer

Messagesは再利用できるため、作成されるオブジェクトとGCが少なくなります。また、クラスと匿名タイプが少なくなります。

大きな利点の1つは、MessageHandlerに送信するクラスがそのMessageの実装について何も知る必要がないことです。これは、使用場所によってはカプセル化に役立ちます。

最後に、間の清浄度の違いを検討してください

_mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();
_

vs

_final Foo tempFoo = foo;
mHandler.post(new Runnable(){
    @Override
    public void run(){
        doStuff(tempFoo);
    }
};
_

doStuff()が必要な場所が複数ある場合、前者の方がはるかに読みやすく、コードの重複が少なくなります。

12
keyboardr

ドキュメントによると、HandlerインターフェースはrunOnUiThread()よりもはるかに多くの機能を提供します。

ハンドラーの主な用途は2つあります。
(1)メッセージとランナブルを将来のある時点で実行するようにスケジュールする
(2)自分のスレッドとは異なるスレッドで実行されるアクションをキューに入れます。

runOnUiThreadは(2)のサブセットのみを実行します。つまり、「実行するアクションをキューに入れてUIスレッド "

したがって、これらの追加機能が必要でない限り、IMOはrunOnUiThreadで十分で好ましい方法です。

4
Caner

RunnableよりもMessageの方が好きです。イベント処理コードはイベントに非常に近いため、Runnableを使用するコードはMessageよりもはるかに明確だと思います。また、定数とスイッチケースを定義するオーバーヘッドを回避できます。

そして、Runnableの使用がカプセル化に違反するとは思いません。 Runnable.run()のコードを外部クラスの別のメソッド(たとえばon...Event())に抽出したり、EventHandlerオブジェクトにラップしたりすることもできます。どちらの方法も、Messageを使用するよりもはるかに明確です。特に、Messageにストア参照が必要な場合は、Runnableを使用するとmsg.objのダウンキャストが回避されるためです。また、名前のないフィールドmsg.objもエラーが発生しやすく、理解するのが非効率的である場合があります。

また、Runnableは、フィールドとして保存することで再利用することもできます。

2
ProtossShuttle