Niewielkie różnice w stosunku do mojego innego wpisu
Zasadniczo mam Handler
w moim komunikacie, Fragment
który odbiera kilka wiadomości, które mogą spowodować zamknięcie lub wyświetlenie okien dialogowych.
Kiedy aplikacja jest umieszczona w tle, otrzymuję komunikat, onPause
ale nadal otrzymuję wiadomości zgodnie z oczekiwaniami. Jednak ponieważ używam fragmentów, nie mogę po prostu odrzucić i pokazać okien dialogowych, ponieważ spowoduje to, że plik IllegalStateException
.
Nie mogę po prostu odrzucić ani anulować zezwolenia na utratę stanu.
Biorąc pod uwagę, że mam a Handler
, zastanawiam się, czy istnieje zalecane podejście do tego, jak powinienem obsługiwać wiadomości w stanie wstrzymania.
Jednym z możliwych rozwiązań, które rozważam, jest nagrywanie wiadomości przychodzących podczas wstrzymania i odtwarzanie ich w formacie onResume
. Jest to trochę niezadowalające i myślę, że musi być coś w ramach, aby poradzić sobie z tym bardziej elegancko.
Odpowiedzi:
Chociaż wydaje się, że system operacyjny Android nie ma mechanizmu, który dostatecznie rozwiązuje Twój problem, uważam, że ten wzorzec zapewnia stosunkowo proste do zaimplementowania obejście.
Poniższa klasa jest opakowaniem,
android.os.Handler
które buforuje wiadomości, gdy działanie jest wstrzymane i odtwarza je po wznowieniu.Upewnij się, że każdy posiadany kod, który asynchronicznie zmienia stan fragmentu (np. Zatwierdzenie, odrzucenie), jest wywoływany tylko z komunikatu w module obsługi.
Wyprowadź swojego handlera z
PauseHandler
klasy.Zawsze, gdy Twoja aktywność odbiera
onPause()
telefonPauseHandler.pause()
ionResume()
dzwoniPauseHandler.resume()
.Wymień realizację Handler
handleMessage()
zprocessMessage()
.Zapewnij prostą implementację,
storeMessage()
która zawsze wracatrue
.Poniżej znajduje się prosty przykład wykorzystania tej
PausedHandler
klasy.Kliknięcie przycisku powoduje wysłanie opóźnionej wiadomości do programu obsługi.
Gdy program obsługi odbiera komunikat (w wątku interfejsu użytkownika), wyświetla plik
DialogFragment
.Jeśli
PausedHandler
klasa nie była używana, wyjątek IllegalStateException byłby wyświetlany, jeśli przycisk strony głównej został naciśnięty po naciśnięciu przycisku testowego w celu uruchomienia okna dialogowego.Dodałem
storeMessage()
doPausedHandler
klasy metodę na wypadek, gdyby jakiekolwiek wiadomości były przetwarzane natychmiast, nawet gdy działanie jest wstrzymane. Jeśli wiadomość jest obsługiwana, należy zwrócić false, a wiadomość zostanie odrzucona.źródło
resume
metoda wykorzystujesendMessage(msg)
technicznie, mogą istnieć inne wątki kolejkujące wiadomość tuż przed (lub pomiędzy iteracjami pętli), co oznacza, że przechowywane wiadomości mogą być przeplatane nowymi wiadomościami. Nie jestem pewien, czy to wielka sprawa. Może użyciesendMessageAtFrontOfQueue
(i oczywiście iteracja wstecz) rozwiązałoby ten problem?Nieco prostszą wersją doskonałego PauseHandler ekspresu jest
Zakłada się, że zawsze chcesz przechowywać wiadomości offline do ponownego odtworzenia. I zapewnia działanie jako dane wejściowe,
#processMessages
więc nie musisz zarządzać nim w podklasie.źródło
resume()
ipause()
, ihandleMessage
synchronized
?Oto nieco inny sposób podejścia do problemu wykonywania zatwierdzeń fragmentów w funkcji wywołania zwrotnego i unikania problemu IllegalStateException.
Najpierw utwórz niestandardowy interfejs, który można uruchomić.
Następnie utwórz fragment do przetwarzania obiektów MyRunnable. Jeśli obiekt MyRunnable został utworzony po wstrzymaniu działania, np. W przypadku obrócenia ekranu lub naciśnięcia przycisku głównego przez użytkownika, jest on umieszczany w kolejce do późniejszego przetwarzania z nowym kontekstem. Kolejka przetrwa wszelkie zmiany konfiguracji, ponieważ instancja setRetain ma wartość true. Metoda runProtected działa w wątku interfejsu użytkownika, aby uniknąć sytuacji wyścigu z flagą isPaused.
Wreszcie fragment można wykorzystać w głównej aplikacji w następujący sposób:
źródło
W moich projektach używam wzorca projektowego obserwatora, aby rozwiązać ten problem. W systemie Android odbiorniki i intencje transmisji są realizacją tego wzorca.
Co mogę zrobić, to stworzyć BroadcastReceiver który zarejestrować się fragment w / działalności za onResume i wyrejestrowywanie w fragment w / działalności za OnPause . W metodzie BroadcastReceiver onReceive umieściłem cały kod, który musi zostać uruchomiony w wyniku - BroadcastReceiver - odebrania intencji (wiadomości), która została wysłana do Twojej aplikacji. Aby zwiększyć selektywność co do typu intencji, jaki może otrzymać Twój fragment, możesz użyć filtra intencji jak w poniższym przykładzie.
Zaletą tego podejścia jest to, że intencja (wiadomość) może być wysyłana z dowolnego miejsca w aplikacji (okno dialogowe, które otwiera się na górze Twojego fragmentu, zadanie asynchroniczne, inny fragment itp.). Parametry mogą być nawet przekazywane jako dodatki intencyjne.
Kolejną zaletą jest to, że to podejście jest kompatybilne z każdą wersją interfejsu API Androida, ponieważ BroadcastReceivers i Intents zostały wprowadzone na poziomie API 1.
Nie musisz ustawiać żadnych specjalnych uprawnień w pliku manifestu swojej aplikacji, chyba że planujesz używać sendStickyBroadcast (gdzie musisz dodać BROADCAST_STICKY).
źródło