サービスからUIスレッドハンドラーにアクセスする


89

私は、UIスレッドのハンドラーにアクセスする必要があるAndroidで新しいことを試しています。

私は次のことを知っています:

  1. UIスレッドには独自のハンドラーとルーパーがあります
  2. メッセージはすべてUIスレッドのメッセージキューに入れられます
  3. ルーパーはイベントを取得してハンドラーに渡しました
  4. ハンドラーがメッセージを処理し、特定のイベントをUIに送信します

UIスレッドハンドラーを取得し、このハンドラーにメッセージを送信する必要があるサービスが必要です。このメッセージが処理され、UIに発行されるようにします。ここでサービスは、いくつかのアプリケーションによって開始される通常のサービスになります。

これが可能かどうか知りたいのですが。もしそうなら、私がそれを試すことができるように、いくつかのコードスニペットを提案してください。

よろしくお願いします

回答:


179

このコードスニペットは、メイン(UI)スレッドに関連付けられたハンドラーを作成します。

Handler handler = new Handler(Looper.getMainLooper());

次に、次のようにメイン(UI)スレッドで実行するものを投稿できます。

handler.post(runnable_to_call_from_main_thread);

ハンドラー自体がメイン(UI)スレッドから作成されている場合、簡潔にするために引数を省略できます。

Handler handler = new Handler();

Androidのデベロッパーガイドプロセスとスレッドについては、より多くの情報を持っています。


2
テストしてみました。ユースケースの例:デバイスで直接実行されているサーバーによって提供されているWebインターフェイスがあります。インターフェイスを使用してUIを直接操作できるため、サーバーは独自のスレッドで実行する必要があるため、アクティビティの外部からUIスレッドに触れる方法が必要でした。あなたが説明した方法はうまくいきました。
mrPjer

1
鮮やかさ。魅力のように機能し、非常に便利です。ありがとうございました。
JRun 2013

パーフェクト^^ StreamingServiceから私のUIを更新するために使用しました。本当に必要なものに感謝します!
An-droid 2014年

ハンドラーのシングルトンインスタンスを作成し、UIスレッドで何かを実行する必要があるたびにそれを使用できるかどうかを知っていますか?
HelloWorld

私たちは決して知ることはないと思います
デニー

28

Messengerアタッチされたオブジェクトを作成し、HandlerそれMessengerService(たとえばのIntentエクストラでstartService())に渡します。Serviceその後、送信することができますMessageHandler経由Messenger。これを示すサンプルアプリケーションを次に示します。


このヒントをありがとう。これは役に立ちました。MyDemo.dispatchTouchEvent(MotionEvent)行へのタッチイベントフローについては、次のスタックを参照してください:20 PhoneWindow $ DecorView.dispatchTouchEvent(MotionEvent)行:1696 ViewRoot.handleMessage(Message)行:1658 ViewRoot(Handler).dispatchMessage(Message )行:99 Looper.loop()行:123 //ここでイベント処理を開始ActivityThread.main(String [])行:4203ここでViewRootはハンドラーです。このハンドラの参照を取得したい...私のアプリケーションからこれを取得することは可能ですか?
iLikeAndroid

@iLikeAndroid:を作成しなかった場合Handler、AFAIKにアクセスできません。
CommonsWare

ありがとうございました。ViewRootのインスタンスを作成しようとしました。これはハンドラにすぎません。これで、このハンドラーでメッセージを発行できます。ハンドラーがメッセージを取得しています。しかし、ViewRootは適切に初期化されていないため、メッセージを処理できません。適切なデータをViewRootに初期化するには、ViewRoot.setView()を呼び出す必要があります。初期化に使用できるデフォルトビューやベースビューなどがあるかどうかを知りたいのですが。
iLikeAndroid

@iLikeAndroid:ViewRootAndroid SDK AFAICTにはありません。
CommonsWare

1
@ hadez30:個人的に、私はバインドされたサービスをあまり使用していません。Handler/ を使用することもできますが、Messengerすべてをイベ​​ントバス(たとえば、greenrobotのEventBus)に置き換えます。
CommonsWare、2015年

4

現時点では、この種の問題にはOttoなどのイベントバスライブラリの使用を好みます。必要なコンポーネント(アクティビティ)をサブスクライブするだけです。

protected void onResume() {
    super.onResume();
    bus.register(this);
}

次に、コールバックメソッドを提供します。

public void onTimeLeftEvent(TimeLeftEvent ev) {
    // process event..
}

そしてあなたのサービスがこのようなステートメントを実行するとき:

bus.post(new TimeLeftEvent(340));

そのPOJOは、上記のアクティビティと他のすべてのサブスクライブコンポーネントに渡されます。シンプルでエレガント。


3

私は次のコードを試すことをお勧めします:

    new Handler(Looper.getMainLooper()).post(() -> {

        //UI THREAD CODE HERE



    });

OPを支援するには、追加の説明が必要です。
Moog

2

次のように、ブロードキャストレシーバーを介して値を取得できます。まず、次のように独自のIntentFilterを作成します。

Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");

次に、内部クラスBroadcastReceiverを次のように作成します。

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    /** Receives the broadcast that has been fired */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction()=="YOUR_INTENT_FILTER"){
           //HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
           String receivedValue=intent.getStringExtra("KEY");
        }
    }
};

次に、ブロードキャストレシーバーをonResume()に登録します。

registerReceiver(broadcastReceiver, intentFilter);

最後に、onDestroy()でBroadcastReceiverの登録を解除します。

unregisterReceiver(broadcastReceiver);

ここで最も重要な部分...値を送信する必要がある場所からブロードキャストを起動する必要があります.....

Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);

....乾杯:)


1

kotlinthatsあなたはそれを行うことができますどのように

サービスからのトーストメッセージを表示する場合は、

val handler = Handler(Looper.getMainLooper())
handler.post {
   Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}

0

解決:

  1. メインスレッドからルーパーを使用してハンドラーを作成する:requestHandler
  2. 作成HandlerLooper、メインスレッドから:するResponseHandlerとオーバーライドhandleMessageメソッド
  3. 投稿のRunnableのRequestHandler上のタスクを
  4. Runnableタスク内で、responseHandlerのsendMessageを呼び出します
  5. これsendMessageにより、responseHandlerでhandleMessageが呼び出されます。
  6. から属性を取得してMessage処理し、UIを更新する

サンプルコード:

    /* Handler from UI Thread to send request */

    Handler requestHandler = new Handler(Looper.getMainLooper());

     /* Handler from UI Thread to process messages */

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {

            /* Processing handleMessage */

            Toast.makeText(MainActivity.this,
                    "Runnable completed with result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<10; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {
                   /* Send an Event to UI Thread through message. 
                      Add business logic and prepare message by 
                      replacing example code */

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.