W usłudze Androida utworzyłem wątki do wykonania zadania w tle.
Mam sytuację, w której wątek musi opublikować określone zadanie w kolejce komunikatów głównego wątku, na przykład a Runnable
.
Czy istnieje sposób, aby uzyskać Handler
od głównego wątku i post Message
/ Runnable
do niego z moim innym wątku?
Dzięki,
Odpowiedzi:
UWAGA: Na tę odpowiedź zwrócono tak dużą uwagę, że muszę ją zaktualizować. Od czasu opublikowania oryginalnej odpowiedzi komentarz @dzeikei zyskał prawie tyle samo uwagi, co oryginalna odpowiedź. Oto 2 możliwe rozwiązania:
1. Jeśli wątek w tle ma odniesienie do
Context
obiektu:Upewnij się, że wątki procesu roboczego w tle mają dostęp do obiektu Context (może to być kontekst aplikacji lub kontekst usługi). Następnie po prostu zrób to w wątku procesu roboczego w tle:
2. Jeśli wątek w tle nie ma (lub nie potrzebuje)
Context
obiektu(sugerowane przez @dzeikei):
źródło
Handler
(lub używaszHandler.Callback
interfejsu), twojahandleMessage()
metoda będzie wywoływana TYLKO dla wiadomości, które zostały opublikowane za pomocą twojego programu obsługi. Główny wątek używa innej procedury obsługi do wysyłania / przetwarzania wiadomości, więc nie ma konfliktu.Handler mainHandler = new Handler(Looper.getMainLooper());
new Runnable(){@Override public void run() {....}};
Jak komentator poniżej wskazał poprawnie, nie jest to ogólne rozwiązanie dla usług, tylko dla wątków uruchamianych z twojej aktywności (usługa może być takim wątkiem, ale nie wszystkie z nich są). Na skomplikowany temat komunikacji między usługami a usługami proszę przeczytać całą sekcję Usługi oficjalnego dokumentu - jest skomplikowana, więc opłaca się zrozumieć podstawy: http://developer.android.com/guide/components/services.html # Powiadomienia
Poniższa metoda może działać w najprostszych przypadkach.
Jeśli dobrze cię rozumiem, potrzebujesz kodu do wykonania w wątku GUI aplikacji (nie mogę myśleć o niczym innym, co nazywa się „głównym” wątkiem). W tym celu istnieje metoda
Activity
:Dokument: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29
Mam nadzieję, że tego właśnie szukasz.
źródło
Service
. Nie możesz użyćrunOnUiThread()
wService
. Ta odpowiedź jest myląca i nie odnosi się do zadanego pytania.Istnieje inny prosty sposób, jeśli nie masz dostępu do kontekstu.
1). Utwórz moduł obsługi z głównego looper'a:
2). Zaimplementuj interfejs Runnable:
3). Opublikuj Runnable w uiHandler:
To wszystko ;-) Baw się dobrze z wątkami, ale nie zapomnij ich zsynchronizować.
źródło
Jeśli uruchamiasz kod w wątku, np. Opóźniasz jakieś działanie, musisz wywołać
runOnUiThread
z kontekstu. Na przykład, jeśli kod znajduje się wMainActivity
klasie, użyj tego:Jeśli twoją metodę można wywołać albo z głównego (wątek interfejsu użytkownika), albo z innych wątków, musisz sprawdzić:
źródło
Service
. Nie możesz użyćrunOnUiThread()
wService
.Activity
dokumentacji,runOnUiThread()
jest to metodaActivity
. Nie jest to metodaService
, dlatego nie można jej użyć. Co może być bardziej zrozumiałe?Skondensowany blok kodu jest następujący:
Nie obejmuje to przekazywania odwołania do działania lub odwołania do aplikacji.
Odpowiednik Kotlin:
źródło
Wersje Kotlin
Kiedy jesteś na aktywności , użyj
Gdy masz kontekst działania , mContext następnie użyj
Jeśli jesteś w miejscu, w którym nie ma dostępnego kontekstu , użyj
źródło
runOnUiThread(){...}
Najprostszy sposób, zwłaszcza jeśli nie masz kontekstu, jeśli używasz RxAndroid, możesz:
źródło
Bardziej precyzyjny kod Kotlin za pomocą programu obsługi:
źródło
Jedną z metod, o której mogę myśleć, jest:
1) Pozwól interfejsowi użytkownika powiązać się z usługą.
2) Podaj metodę podobną do poniższej,
Binder
która rejestruje twojeHandler
:3) W wątku interfejsu użytkownika wywołaj powyższą metodę po powiązaniu z usługą:
4) Użyj modułu obsługi w wątku usługi, aby opublikować swoje zadanie:
źródło
HandlerThread
jest lepszą opcją dla normalnych wątków Java w Androidzie.requestHandler
post
Runnable
zadanie narequestHandler
Komunikacja z wątkiem interfejsu użytkownika z
HandlerThread
Handler
withLooper
dla głównego wątku:responseHandler
i przesłonięciahandleMessage
Runnable
zadania innym wątku (HandlerThread
w tym przypadku), zadzwońsendMessage
naresponseHandler
sendMessage
wywołanie wynikuhandleMessage
wresponseHandler
.Message
i przetworz je, zaktualizuj interfejs użytkownikaPrzykład : aktualizacja
TextView
danych otrzymanych z usługi internetowej. Ponieważ usługa sieci web powinna być wywoływana w wątku innym niż interfejs użytkownika, utworzonymHandlerThread
do działania w sieci. Po pobraniu treści z usługi internetowej wyślij wiadomość do głównego modułu obsługi wątku (wątku interfejsu użytkownika),Handler
który obsłuży komunikat i zaktualizuje interfejs użytkownika.Przykładowy kod:
Przydatne artykuły:
handlerthreads-and-dlaczego-you-should-be-using-them-in-your-android-apps
android-looper-handler-handlerthread-i
źródło
Wiem, że to stare pytanie, ale natknąłem się na główny wątek, którego używam zarówno w Kotlinie, jak i Javie. To może nie być najlepsze rozwiązanie dla usługi, ale wywołanie czegoś, co zmieni interfejs użytkownika wewnątrz fragmentu, jest niezwykle proste i oczywiste.
Java (8):
Kotlin:
źródło
Postępuj zgodnie z tą metodą. W ten sposób możesz po prostu zaktualizować interfejs użytkownika z wątku w tle. praca runOnUiThread w wątku głównym (UI). Myślę, że ten fragment kodu jest mniej złożony i łatwy, szczególnie dla początkujących.
w przypadku usługi
utwórz moduł obsługi w utworzonym pliku
następnie użyj tego w ten sposób
źródło
w przypadku Kotlina można używać kontenów Anko :
aktualizacja
przestarzałe
źródło
Najbardziej przydatne jest zrobienie czegoś takiego:
I po:
źródło
Może to również działać bez problemu w klasie usług.
źródło
Z Kotlin jest tak w każdej funkcji:
źródło
Activity
.