Uzyskiwanie dostępu do programu obsługi wątków interfejsu użytkownika z usługi

90

Próbuję czegoś nowego w systemie Android, dla którego muszę uzyskać dostęp do programu obsługi wątku interfejsu użytkownika.

Wiem co następuje:

  1. Wątek interfejsu użytkownika ma własny program obsługi i pętlę
  2. Każda wiadomość zostanie umieszczona w kolejce komunikatów wątku interfejsu użytkownika
  3. Looper odbiera zdarzenie i przekazuje je do procedury obsługi
  4. Program obsługi obsługuje komunikat i wysyła określone zdarzenie do interfejsu użytkownika

Chcę mieć moją usługę, która musi pobrać program obsługi wątków interfejsu użytkownika i umieścić komunikat w tym programie obsługi. Aby ta wiadomość została przetworzona i wysłana do interfejsu użytkownika. W tym przypadku usługa będzie normalną usługą uruchamianą przez jakąś aplikację.

Chciałbym wiedzieć, czy jest to możliwe. Jeśli tak, to proszę zasugeruj fragmenty kodu, abym mógł spróbować.

Pozdrawiam Girish

iLikeAndroid
źródło

Odpowiedzi:

179

Ten fragment kodu tworzy Handler skojarzony z wątkiem głównym (UI):

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

Następnie możesz publikować rzeczy do wykonania w głównym wątku (UI) w następujący sposób:

handler.post(runnable_to_call_from_main_thread);

Jeśli sam program obsługi został utworzony z głównego (UI) wątku, argument można pominąć dla zwięzłości:

Handler handler = new Handler();

Android Dev przewodnik na temat procesów i wątków ma więcej informacji.

salwa
źródło
2
Przetestowałem to i działa świetnie! Przykład przypadku użycia: Mam interfejs WWW, który jest obsługiwany przez serwer działający bezpośrednio na urządzeniu. Ponieważ interfejs może być używany do bezpośredniej interakcji z interfejsem użytkownika, a serwer musi działać we własnym wątku, potrzebowałem sposobu na dotknięcie wątku interfejsu użytkownika spoza działania. Metoda, którą opisałeś, działała świetnie.
mrPjer
1
Znakomity. Działa jak urok i bardzo przydatne. DZIĘKUJĘ CI.
JRun
perfect ^^ właśnie użyłem go do zaktualizowania mojego interfejsu użytkownika z usługi StreamingService. dokładnie to, czego potrzebowałem, dzięki!
An-droid
Czy wiesz, czy mogę utworzyć pojedynczą instancję procedury obsługi i używać jej za każdym razem, gdy muszę uruchomić coś w wątku interfejsu użytkownika?
HelloWorld
Chyba nigdy się nie dowiemy
Denny,
28

Utwórz Messengerobiekt dołączony do twojego Handleri przekaż Messengergo do Service(np. W Intentdodatkowym for startService()). ServiceMożna następnie wysłać Messagedo Handlerza pośrednictwem Messenger. Oto przykładowa aplikacja , która to demonstruje.

CommonsWare
źródło
Dzięki za tę wskazówkę. To było pomocne. Zobacz następujący stos dla przepływu zdarzeń dotyku do mojej aktywności MyDemo.dispatchTouchEvent (MotionEvent) wiersz: 20 PhoneWindow $ DecorView.dispatchTouchEvent (MotionEvent) wiersz: 1696 ViewRoot.handleMessage (Message) wiersz: 1658 ViewRoot (Handler) .dispatchMessage (Message) ) line: 99 Looper.loop () line: 123 // Tutaj rozpoczyna się obsługa zdarzeń ActivityThread.main (String []) line: 4203 Tutaj ViewRoot jest Handlerem. Chcę uzyskać odniesienie do tego programu obsługi ... czy można to uzyskać z mojej aplikacji?
iLikeAndroid
@iLikeAndroid: Jeśli nie utworzyłeś Handler, nie możesz uzyskać do niego dostępu, AFAIK.
CommonsWare,
Dziękuję Ci. Próbowałem utworzyć wystąpienie ViewRoot. To nic innego jak przewodnik. Teraz mogę wysyłać komunikaty do tego programu obsługi. Program obsługi odbiera wiadomość. Ale ViewRoot nie jest w stanie przetworzyć wiadomości, ponieważ nie jest poprawnie zainicjowany. Muszę wywołać ViewRoot.setView (), aby zainicjować odpowiednie dane do ViewRoot. Chcę wiedzieć, czy istnieje widok domyślny lub widok bazowy itp., Których mogę użyć do inicjalizacji?
iLikeAndroid,
@iLikeAndroid: W ViewRootAndroid SDK nie ma AFAICT.
CommonsWare
1
@ hadez30: Osobiście rzadko korzystam z usług związanych. Nadal możesz używać Handler/ Messenger, chociaż zastąpiłbym to wszystko magistralą zdarzeń (np. EventBus firmy greenrobot).
CommonsWare
4

W tej chwili wolę korzystać z biblioteki event bus, takiej jak Otto do tego rodzaju problemów. Po prostu zasubskrybuj wybrane komponenty (aktywność):

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

Następnie podaj metodę wywołania zwrotnego:

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

a następnie, gdy twoja usługa wykona instrukcję taką jak ta:

bus.post(new TimeLeftEvent(340));

To POJO zostanie przekazane do twojego powyższego działania i wszystkich innych składników subskrybujących. Prosty i elegancki.

wózek dziecięcy
źródło
3

Proponuję wypróbować następujący kod:

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

        //UI THREAD CODE HERE



    });
user2983041
źródło
Aby pomóc PO, wymagane są dodatkowe wyjaśnienia.
Moog
2

Możesz uzyskać wartości przez odbiornik rozgłoszeniowy ...... w następujący sposób: Najpierw utwórz swój własny filtr IntentFilter jako,

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

Następnie utwórz wewnętrzną klasę BroadcastReceiver as,

    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");
        }
    }
};

Teraz zarejestruj odbiornik transmisji w onResume () jako,

registerReceiver(broadcastReceiver, intentFilter);

I wreszcie wyrejestruj BroadcastReceiver w onDestroy () as,

unregisterReceiver(broadcastReceiver);

Teraz najważniejsza część ... Musisz odpalić transmisję z dowolnego miejsca, w którym chcesz wysłać wartości ..... więc zrób tak,

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

....Twoje zdrowie :)

Melbourne Lopes
źródło
1

W ten kotlinsposób możesz to zrobić

Powiedzmy, czy chcesz wyświetlić wiadomość Toast z usługi

val handler = Handler(Looper.getMainLooper())
handler.post {
   Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}
Zohab Ali
źródło
0

Rozwiązanie:

  1. Utwórz Handler z Looper z głównego wątku: requestHandler
  2. Utwórz Handlerz Looperz głównego wątku: responseHandler i przesłonhandleMessage metoda
  3. opublikuj Runnable zadanie na requestHandler
  4. Wewnątrz Runnable zadania wywołaj sendMessage na responseHandler
  5. To sendMessage powoduje wywołanie handleMessage w responseHandler.
  6. Pobierz atrybuty z Messagei przetwórz je, zaktualizuj interfejs użytkownika

Przykładowy kod:

    /* 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);
    }
Ravindra babu
źródło