Mój program wykonuje pewną aktywność sieciową w wątku w tle. Przed rozpoczęciem pojawia się okno dialogowe postępu. Okno dialogowe zostaje zamknięte w module obsługi. To wszystko działa dobrze, z wyjątkiem sytuacji, gdy orientacja ekranu zmienia się, gdy okno dialogowe jest uruchomione (a wątek w tle się rozwija). W tym momencie aplikacja ulega awarii, blokuje się lub przechodzi w dziwny etap, w którym aplikacja w ogóle nie działa, dopóki wszystkie wątki nie zostaną zabite.
Jak mogę płynnie obsługiwać zmianę orientacji ekranu?
Przykładowy kod poniżej odpowiada mniej więcej temu, co robi mój prawdziwy program:
public class MyAct extends Activity implements Runnable {
public ProgressDialog mProgress;
// UI has a button that when pressed calls send
public void send() {
mProgress = ProgressDialog.show(this, "Please wait",
"Please wait",
true, true);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Thread.sleep(10000);
Message msg = new Message();
mHandler.sendMessage(msg);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgress.dismiss();
}
};
}
Stos:
E/WindowManager( 244): Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): android.view.WindowLeaked: Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): at android.view.ViewRoot.<init>(ViewRoot.java:178)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:147)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
E/WindowManager( 244): at android.view.Window$LocalWindowManager.addView(Window.java:393)
E/WindowManager( 244): at android.app.Dialog.show(Dialog.java:212)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:103)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:91)
E/WindowManager( 244): at MyAct.send(MyAct.java:294)
E/WindowManager( 244): at MyAct$4.onClick(MyAct.java:174)
E/WindowManager( 244): at android.view.View.performClick(View.java:2129)
E/WindowManager( 244): at android.view.View.onTouchEvent(View.java:3543)
E/WindowManager( 244): at android.widget.TextView.onTouchEvent(TextView.java:4664)
E/WindowManager( 244): at android.view.View.dispatchTouchEvent(View.java:3198)
Próbowałem zamknąć okno dialogowe postępu w onSaveInstanceState, ale to po prostu zapobiega natychmiastowej awarii. Wątek w tle nadal działa, a interfejs użytkownika jest częściowo narysowany. Musisz zabić całą aplikację, zanim zacznie ponownie działać.
źródło
Odpowiedzi:
Po zmianie orientacji system Android utworzy nowy widok. Prawdopodobnie masz awarie, ponieważ twój wątek w tle próbuje zmienić stan na stary. (Może to również powodować problemy, ponieważ wątek w tle nie znajduje się w wątku interfejsu użytkownika)
Sugerowałbym uczynienie tego mHandlera niestabilnym i aktualizowanie go, gdy zmienia się orientacja.
źródło
Edycja: inżynierowie Google nie zalecają takiego podejścia, zgodnie z opisem Dianne Hackborn (alias hackbod ) w tym poście StackOverflow . Sprawdź ten post na blogu, aby uzyskać więcej informacji.
Musisz dodać to do deklaracji aktywności w manifeście:
tak to wygląda
Chodzi o to, że system niszczy działanie, gdy nastąpi zmiana konfiguracji. Zobacz Zmiana konfiguracji .
Umieszczenie tego w pliku konfiguracyjnym pozwala uniknąć zniszczenia systemu przez system. Zamiast tego wywołuje
onConfigurationChanged(Configuration)
metodę.źródło
orientation
istnieje wiele innych powodów, dla których należy zmienić konfigurację:keyboardHidden
(Już edytowałem odpowiedź wiki),uiMode
(Na przykład wchodzenie lub wychodzenie z trybu samochodowego; zmiana trybu nocnego) itp. Teraz zastanawiam się, czy tak naprawdę jest dobra odpowiedź.Wymyśliłem solidne rozwiązanie tych problemów, które jest zgodne z „Android Way” rzeczy. Mam wszystkie moje długotrwałe operacje przy użyciu wzorca IntentService.
Oznacza to, że moje działania nadają intencje, IntentService wykonuje pracę, zapisuje dane w bazie danych, a następnie rozgłasza lepkie intencje. Ta lepka część jest ważna, ponieważ nawet jeśli działanie zostało wstrzymane w czasie, gdy użytkownik zainicjował pracę i przegapi transmisję w czasie rzeczywistym z usługi IntentService, nadal możemy odpowiedzieć i odebrać dane z wywołania działania.
ProgressDialog
s może całkiem dobrze pracować z tym wzoremonSaveInstanceState()
.Zasadniczo musisz zapisać flagę, w której oknie dialogowym postępu uruchomiono pakiet zapisanej instancji. Nie zapisuj obiektu dialogowego postępu, ponieważ spowoduje to wyciek całej aktywności. Aby mieć trwały uchwyt okna dialogowego postępu, przechowuję go jako słabe odwołanie w obiekcie aplikacji. Po zmianie orientacji lub cokolwiek innego, co powoduje wstrzymanie działania (połączenie telefoniczne, użytkownik trafia do domu itp.), A następnie wznowienie, zamykam stare okno dialogowe i odtwarzam nowe okno dialogowe w nowo utworzonym działaniu.
W przypadku okien dialogowych postępu na czas nieokreślony jest to łatwe. Aby uzyskać styl paska postępu, musisz umieścić ostatni znany postęp w pakiecie i wszelkie informacje, których używasz lokalnie w działaniu, aby śledzić postęp. Po przywróceniu postępów wykorzystasz te informacje do ponownego pojawienia się paska postępu w tym samym stanie, co poprzednio, a następnie zaktualizujesz na podstawie aktualnego stanu rzeczy.
Podsumowując, umieszczenie długoterminowych zadań w usłudze IntentService w połączeniu z rozsądnym użyciem
onSaveInstanceState()
pozwala efektywnie śledzić okna dialogowe i przywracać je w trakcie zdarzeń cyklu życia działania. Odpowiednie fragmenty kodu aktywności znajdują się poniżej. Będziesz także potrzebował logiki w swoim BroadcastReceiver, aby odpowiednio obsługiwać Lepkie zamiary, ale to wykracza poza zakres tego.źródło
Spotkałem ten sam problem. Moja aktywność musi analizować niektóre dane z adresu URL i jest powolna. Dlatego tworzę wątek, aby to zrobić, a następnie wyświetlam okno dialogowe postępu. Pozwalam, aby wątek wysłał wiadomość z powrotem do wątku interfejsu użytkownika,
Handler
gdy jest ona ukończona. WHandler.handleMessage
otrzymuję obiekt danych (teraz gotowy) z wątku i wypełniam go w interfejsie użytkownika. Więc jest bardzo podobny do twojego przykładu.Po wielu próbach i błędach wygląda na to, że znalazłem rozwiązanie. Przynajmniej teraz mogę obrócić ekran w dowolnym momencie, przed lub po zakończeniu nici. We wszystkich testach okno dialogowe jest poprawnie zamknięte, a wszystkie zachowania są zgodne z oczekiwaniami.
To, co zrobiłem, pokazano poniżej. Celem jest wypełnienie mojego modelu danych (
mDataObject
), a następnie wypełnienie go w interfejsie użytkownika. Powinien umożliwiać obracanie ekranu w dowolnym momencie bez zaskoczenia.To działa dla mnie. Nie wiem, czy jest to „poprawna” metoda zaprojektowana przez Androida - twierdzą, że „niszczenie / odtwarzanie aktywności podczas obracania ekranu” faktycznie ułatwia rzeczy, więc myślę, że nie powinno to być zbyt trudne.
Daj mi znać, jeśli zauważysz problem w moim kodzie. Jak powiedziano powyżej, tak naprawdę nie wiem, czy jest jakiś efekt uboczny.
źródło
onRetainNonConfigurationInstance()
igetLastNonConfigurationInstance()
pomogła mi rozwiązać problem. Kciuki w górę!Pierwotnie postrzegany problem polegał na tym, że kod nie przetrwał zmiany orientacji ekranu. Najwyraźniej zostało to „rozwiązane”, ponieważ program sam obsługiwał zmianę orientacji ekranu, zamiast pozwalać na to interfejsowi użytkownika (poprzez wywołanie onDestroy).
Chciałbym twierdzić, że jeśli podstawowym problemem jest to, że program nie przetrwa onDestroy (), wówczas przyjęte rozwiązanie jest tylko obejściem, które pozostawia program z poważnymi innymi problemami i lukami. Pamiętaj, że system Android wyraźnie stwierdza, że twoja aktywność jest zagrożona zniszczeniem prawie w dowolnym momencie z powodu okoliczności poza Twoją kontrolą. Dlatego twoja aktywność musi być w stanie przetrwać onDestroy () i kolejne onCreate () z dowolnego powodu, a nie tylko zmiany orientacji ekranu.
Jeśli zamierzasz samodzielnie zaakceptować obsługę zmian orientacji ekranu w celu rozwiązania problemu PO, musisz sprawdzić, czy inne przyczyny onDestroy () nie powodują tego samego błędu. Czy potrafisz to zrobić? Jeśli nie, zapytałbym, czy „zaakceptowana” odpowiedź jest naprawdę bardzo dobra.
źródło
Moim rozwiązaniem było rozszerzenie
ProgressDialog
klasy, aby uzyskać własneMyProgressDialog
.Przedefiniowałem
show()
idismiss()
metody blokowania orientacji przed wyświetleniemDialog
i odblokowania, kiedyDialog
zwolnieniu. Tak więc, gdyDialog
pokazuje się i zmienia się orientacja urządzenia, orientacja ekranu pozostaje do momentudismiss()
wywołania, a następnie orientacja ekranu zmienia się zgodnie z wartościami czujnika / orientacją urządzenia.Oto mój kod:
źródło
Napotkałem ten sam problem i wymyśliłem rozwiązanie, które nie ingerowało w program ProgressDialog i uzyskuję szybsze wyniki.
Stworzyłem układ z paskiem postępu.
Następnie w metodzie onCreate wykonaj następujące czynności
Następnie wykonaj długie zadanie w wątku, a kiedy to się skończy, ustaw Runnable w widoku zawartości prawdziwy układ, którego chcesz użyć dla tego działania.
Na przykład:
To właśnie zrobiłem i przekonałem się, że działa szybciej niż pokazuje ProgressDialog i jest mniej inwazyjny i moim zdaniem lepiej wygląda.
Jeśli jednak chcesz użyć ProgressDialog, ta odpowiedź nie jest dla Ciebie.
źródło
setContentView(R.layout.my_layout);
nie jest wystarczający; musisz ustawić wszystkich słuchaczy, zresetować dane itp.Odkryłem rozwiązanie tego, czego jeszcze nie widziałem. Możesz użyć niestandardowego obiektu aplikacji, który wie, czy wykonujesz zadania w tle, zamiast próbować to zrobić w działaniu, które jest niszczone i odtwarzane po zmianie orientacji. Napisałem o tym tutaj blog .
źródło
Application
jest zwykle używane do utrzymania globalnego stanu aplikacji. Nie twierdzę, że to nie działa, ale wydaje się to zbyt skomplikowane. Z dokumentu „Zwykle nie ma potrzeby podklasowania aplikacji.”. W dużej mierze wolę odpowiedź sonxurxo.Mam zamiar przyczynić się do rozwiązania tego problemu z rotacją. Może to nie dotyczyć OP, ponieważ nie używa
AsyncTask
, ale może inni uznają to za przydatne. To dość proste, ale wydaje mi się, że wykonuje to za mnie:Mam aktywność logowania przy użyciu zagnieżdżonej
AsyncTask
klasy o nazwieBackgroundLoginTask
.W moim
BackgroundLoginTask
przypadku nie robię nic niezwykłego oprócz dodania zerowej kontroli poProgressDialog
odrzuceniu połączenia:Ma to na celu obsłużenie przypadku, gdy zadanie w tle kończy się, gdy
Activity
nie jest widoczne, a zatem okno dialogowe postępu zostało już odrzucone przezonPause()
metodę.Następnie w mojej
Activity
klasie nadrzędnej tworzę globalne uchwyty statyczne do mojejAsyncTask
klasy i mojaProgressDialog
(AsyncTask
zagnieżdżona może uzyskać dostęp do tych zmiennych):Służy to dwóm celom: po pierwsze, pozwala mi
Activity
zawsze uzyskać dostęp doAsyncTask
obiektu, nawet z nowej, post-obróconej aktywności. Po drugie, pozwala miBackgroundLoginTask
uzyskać dostęp i zamknąćProgressDialog
nawet po rotacji.Następnie dodaję to do
onPause()
, powodując zniknięcie okna postępu, gdyActivity
opuszczamy pierwszy plan (zapobiegając temu brzydkiemu „przymusowemu zamknięciu” awarii):Wreszcie mam następujące
onResume()
metody:Umożliwia
Dialog
to ponowne pojawienie się poActivity
odtworzeniu.Oto cała klasa:
Nie jestem bynajmniej doświadczonym programistą Androida, więc nie krępuj się komentować.
źródło
Przenieś długie zadanie do oddzielnej klasy. Zaimplementuj go jako wzorzec podmiot-obserwator. Za każdym razem, gdy działanie zostanie utworzone, zarejestruj się i podczas zamykania wyrejestruj się z klasą zadania. Klasa zadania może korzystać z AsyncTask.
źródło
Sztuką jest pokazanie / zamknięcie okna dialogowego w AsyncTask podczas onPreExecute / onPostExecute jak zwykle, jednak w przypadku zmiany orientacji utwórz / pokaż nowe wystąpienie okna dialogowego w działaniu i przekaż jego odwołanie do zadania.
źródło
Zrobiłem to w ten sposób:
Możesz także spróbować dać mi znać, czy to działa dla Ciebie, czy nie
źródło
Jeśli utworzysz tło,
Service
które wykonuje wszystkie ciężkie operacje podnoszenia (żądania / odpowiedzi Tcp, odebranie),View
iActivity
można je zniszczyć i odtworzyć bez wycieku okna lub utraty danych. Pozwala to na zachowanie zalecane przez Androida, polegające na niszczeniu działania przy każdej zmianie konfiguracji (np. Przy każdej zmianie orientacji).Jest to nieco bardziej złożone, ale jest to najlepszy sposób na wywołanie żądania serwera, wstępne / końcowe przetwarzanie danych itp.
Możesz nawet użyć swojego
Service
do kolejkowania każdego żądania do serwera, dzięki czemu łatwo i wydajnie poradzisz sobie z tymi rzeczami.Przewodnik dla deweloperów zawiera pełny rozdział
Services
.źródło
Service
to więcej pracy niż,AsyncTask
ale może być lepszym podejściem w niektórych sytuacjach. To niekoniecznie lepsze, prawda? Biorąc to pod uwagę, nie rozumiem, jak to rozwiązuje problem tego,ProgressDialog
co wyciekło z głównegoActivity
. Gdzie zakładaszProgressDialog
? Gdzie to odrzucasz?Mam implementację, która pozwala zniszczyć działanie po zmianie orientacji ekranu, ale nadal skutecznie niszczy okno dialogowe w odtworzonej aktywności. Używam,
...NonConfigurationInstance
aby dołączyć zadanie w tle do odtworzonego działania. Normalna struktura systemu Android obsługuje odtwarzanie okna dialogowego, nic się tam nie zmienia.Podklasowałem funkcję AsyncTask, dodając pole dla działania „będącego właścicielem” i metodę aktualizacji tego właściciela.
W mojej klasie aktywności dodałem pole
backgroundTask
odnoszące się do „posiadanego” zadania tła i aktualizuję to pole za pomocąonRetainNonConfigurationInstance
igetLastNonConfigurationInstance
.Sugestie dotyczące dalszej poprawy:
backgroundTask
odwołanie w działaniu po zakończeniu zadania, aby zwolnić pamięć lub inne związane z nim zasoby.ownerActivity
odniesienie w zadaniu w tle, zanim działanie zostanie zniszczone, na wypadek, gdyby nie zostało natychmiast odtworzone.BackgroundTask
interfejs i / lub kolekcję, aby umożliwić uruchamianie różnych typów zadań z tego samego działania będącego właścicielem.źródło
Jeśli utrzymasz dwa układy, wszystkie wątki interfejsu użytkownika powinny zostać zakończone.
Jeśli używasz AsynTask, możesz łatwo wywołać
.cancel()
metodę wewnątrzonDestroy()
metody bieżącej aktywności.Więcej informacji na temat AsyncTask można znaleźć w sekcji „Anulowanie zadania” tutaj .
Aktualizacja: Dodano warunek sprawdzania stanu, ponieważ można go anulować tylko wtedy, gdy jest w stanie uruchomionym. Należy również pamiętać, że AsyncTask można wykonać tylko raz.
źródło
Próbowałem wdrożyć rozwiązanie jfelectron , ponieważ jest to „ solidne rozwiązanie tych problemów, które jest zgodne z„ Android Way ”rzeczy, ale zajęło to trochę czasu, aby spojrzeć i zebrać wszystkie wymienione elementy. Skończyło się na tym nieco innym i myślę, że bardziej eleganckie, rozwiązanie zamieszczone tutaj w całości.
Używa usługi IntentService uruchomionej z działania, aby wykonać długo działające zadanie w osobnym wątku. Usługa odpala lepkie cele transmisji do działania, które aktualizuje okno dialogowe. Działanie wykorzystuje metody showDialog (), onCreateDialog () i onPrepareDialog () w celu wyeliminowania konieczności przekazywania trwałych danych w obiekcie aplikacji lub pakiecie saveInstanceState. Powinno to działać bez względu na przerwanie aplikacji.
Klasa aktywności:
Klasa IntentService:
Wpisy pliku manifestu:
przed sekcją aplikacji:
wewnątrz sekcji aplikacji
źródło
Oto moje proponowane rozwiązanie:
void showProgressDialog()
celu można dodać metodę do interfejsu detektora aktywności fragmentu.źródło
Napotkałem tę samą sytuację. Zrobiłem tylko jedną instancję dla mojego okna postępu w całej aplikacji.
Najpierw utworzyłem klasę DialogSingleton, aby uzyskać tylko jedną instancję (wzorzec Singleton)
Jak pokazuję w tej klasie, mam okno dialogowe postępu jako atrybut. Za każdym razem, gdy muszę wyświetlić okno dialogowe postępu, otrzymuję unikalną instancję i tworzę nowy ProgressDialog.
Kiedy skończę zadanie w tle, ponownie wywołuję unikalną instancję i zamykam jej okno dialogowe.
Zapisuję status zadania w tle w moich wspólnych preferencjach. Kiedy obracam ekran, pytam, czy mam zadanie uruchomione dla tego działania: (onCreate)
Kiedy zaczynam uruchamiać zadanie w tle:
Po zakończeniu uruchamiania zadania w tle:
Mam nadzieję, że to pomoże.
źródło
To bardzo stare pytanie, które z jakiegoś powodu pojawiło się na pasku bocznym.
Jeśli zadanie w tle musi przetrwać tylko wtedy, gdy aktywność jest na pierwszym planie, „nowym” rozwiązaniem jest umieszczenie wątku w tle (lub najlepiej
AsyncTask
) w zachowanym fragmencie , jak opisano w tym przewodniku dla programistów oraz w licznych pytaniach i odpowiedziach .Zachowany fragment przetrwa, jeśli aktywność zostanie zniszczona w wyniku zmiany konfiguracji, ale nie w przypadku, gdy aktywność zostanie zniszczona w tle lub na stosie. Dlatego zadanie w tle powinno być nadal przerywane, jeśli
isChangingConfigurations()
ma wartość falseonPause()
.źródło
Jestem świeższy w Androidzie i próbowałem tego i działa.
źródło
Próbowałem WSZYSTKO. Spędziłem dni eksperymentując. Nie chciałem blokować rotacji aktywności. Mój scenariusz to:
Problem polegał na tym, że podczas obracania ekranu każde rozwiązanie w książce zawiodło. Nawet z klasą AsyncTask, która jest prawidłowym sposobem radzenia sobie z tymi sytuacjami na Androidzie. Po obróceniu ekranu bieżący kontekst, z którym pracuje wątek początkowy, zniknie, co zakłóca wyświetlane okno dialogowe. Problemem zawsze był Dialog, bez względu na to, ile sztuczek dodałem do kodu (przekazywanie nowych kontekstów do uruchomionych wątków, utrzymywanie stanów wątków poprzez rotację itp.). Złożoność kodu na końcu była zawsze ogromna i zawsze było coś, co mogło pójść nie tak.
Jedynym rozwiązaniem, które działało dla mnie, była sztuczka Activity / Dialog. To proste i genialne, a wszystko to odporne na rotację:
Zamiast tworzyć okno dialogowe i poprosić o jego pokazanie, utwórz działanie ustawione w manifeście za pomocą Androida: theme = "@ android: style / Theme.Dialog". Wygląda więc jak okno dialogowe.
Zamień showDialog (DIALOG_ID) na startActivityForResult (yourActivityDialog, yourCode);
Użyj onActivityResult w działaniu wywołującym, aby uzyskać wyniki z wykonanego wątku (nawet błędy) i zaktualizować interfejs użytkownika.
W swoim „ActivityDialog” użyj wątków lub AsyncTask do wykonywania długich zadań, a onRetainNonConfigurationInstance, aby zapisać stan „okna dialogowego” podczas obracania ekranu.
Jest to szybkie i działa dobrze. Nadal używam okien dialogowych do innych zadań i AsyncTask do czegoś, co nie wymaga stałego okna dialogowego na ekranie. Ale w tym scenariuszu zawsze wybieram wzorzec Activity / Dialog.
I nie próbowałem tego, ale nawet można zablokować obracanie tego działania / okna dialogowego, gdy wątek jest uruchomiony, przyspieszając rzeczy, jednocześnie umożliwiając obracanie wywoływanego działania.
źródło
Intent
, co jest bardziej restrykcyjne niżObject
dozwolone przezAsyncTask
Obecnie istnieje znacznie wyraźniejszy sposób radzenia sobie z tego rodzaju problemami. Typowe podejście to:
1. Upewnij się, że Twoje dane są odpowiednio oddzielone od interfejsu użytkownika:
Wszystko, co jest procesem w tle, powinno być zachowane
Fragment
(ustaw to za pomocąFragment.setRetainInstance()
. Staje się to „trwałym przechowywaniem danych”, w którym przechowywane są wszystkie dane, które chcesz zachować. Po zdarzeniu zmiany orientacjiFragment
będzie to nadal dostępne w oryginalnym stan przezFragmentManager.findFragmentByTag()
połączenie (podczas jego tworzenia powinieneś nadać mu tag, a nie identyfikator, ponieważ nie jest dołączony do aView
).Zobacz opracowany przewodnik Obsługa zmian w środowisku wykonawczym, aby uzyskać informacje na temat robienia tego poprawnie i dlaczego jest to najlepsza opcja.
2. Upewnij się, że prawidłowo i bezpiecznie łączysz się między procesami w tle a interfejsem użytkownika:
Musisz odwrócić proces łączenia. W tej chwili proces w tle przyłącza się do procesu
View
- zamiast tegoView
powinieneś dołączyć się do procesu w tle. To ma więcej sensu, prawda? WView
„s działanie jest uzależnione od procesu w tle, podczas gdy proces w tle nie jest zależna odView
.To środków zmieniających się link do standardowegoListener
interfejsu. Powiedz, że twój proces (bez względu na to, jaką jest klasę - czy to jestAsyncTask
,Runnable
czy cokolwiek) definiuje aOnProcessFinishedListener
, kiedy proces zostanie zakończony, powinien wywołać tego odbiornika, jeśli istnieje.Ta odpowiedź to ładny zwięzły opis tego, jak zrobić niestandardowe obiekty nasłuchujące.
3. Połącz swój interfejs użytkownika z procesem danych, gdy interfejs użytkownika zostanie utworzony (w tym zmiany orientacji):
Teraz musisz się martwić o powiązanie zadania w tle z obecną
View
strukturą. Jeśli właściwie postępujesz ze zmianami orientacji (a nieconfigChanges
hack, który ludzie zawsze zalecają),Dialog
system odtworzy je ponownie. Jest to ważne, oznacza to, że przy zmianie orientacjiDialog
przywoływane są wszystkie metody cyklu życia. Tak więc w dowolnej z tych metod (onCreateDialog
zazwyczaj jest to dobre miejsce) możesz wykonać połączenie takie jak:Zobacz cykl życia Fragmentu, aby zdecydować, gdzie ustawienie detektora najlepiej pasuje do Twojej indywidualnej implementacji.
Jest to ogólne podejście do zapewnienia solidnego i kompletnego rozwiązania ogólnego problemu zadanego w tym pytaniu. W tej odpowiedzi prawdopodobnie brakuje kilku drobnych elementów, w zależności od indywidualnego scenariusza, ale jest to zazwyczaj najbardziej poprawne podejście do prawidłowej obsługi zdarzeń zmiany orientacji.
źródło
znalazłem i łatwiejsze rozwiązanie do obsługi wątków przy zmianie orientacji. Możesz po prostu zachować statyczne odniesienie do swojej aktywności / fragmentu i sprawdzić, czy jest ono puste przed działaniem na interfejsie użytkownika. Sugeruję też użycie try catch:
źródło
Jeśli masz problem z wykryciem zdarzeń zmiany orientacji w oknie dialogowym NIEZALEŻNYM OD REFERENCJI AKTYWNOŚCI , ta metoda działa wyjątkowo dobrze. Używam tego, ponieważ mam własną klasę dialogową, która może być wyświetlana w wielu różnych działaniach, więc nie zawsze wiem, w której aktywności jest pokazywana. Dzięki tej metodzie nie musisz zmieniać AndroidManifest, martw się o referencje do działań, i nie potrzebujesz niestandardowego okna dialogowego (tak jak ja). Potrzebny jest jednak niestandardowy widok zawartości, aby można było wykryć zmiany orientacji za pomocą tego konkretnego widoku. Oto mój przykład:
Ustawiać
Realizacja 1 - Dialog
Implementacja 2 - AlertDialog.Builder
Realizacja 3 - ProgressDialog / AlertDialog
źródło
Oto moje rozwiązanie, gdy stawiłem temu czoła:
ProgressDialog
nie jestFragment
dzieckiem, więc moja niestandardowa klasa „ProgressDialogFragment
” może się rozszerzyćDialogFragment
, aby zachować okno dialogowe zmian konfiguracji.Istnieją 2 podejścia do rozwiązania tego:
Pierwsze podejście: wykonaj działanie, które wykorzystuje okno dialogowe do zachowania stanu podczas zmiany konfiguracji w pliku manifestu:
To podejście nie jest preferowane przez Google.
Drugie podejście: w
onCreate()
metodzie działania musisz zachować swojąDialogFragment
, odbudowującProgressDialogFragment
ponownie z tytułem i komunikatem w następujący sposób, jeślisavedInstanceState
wartość nie jest zerowa:źródło
Wydaje się, że jest to zbyt „szybkie i brudne”, aby mogło być prawdą, więc proszę wskazać wady, ale znalazłem, że zadziałało ...
W ramach metody onPostExecute mojej AsyncTask po prostu zawinąłem „.dismiss” dla okna dialogowego postępu w bloku try / catch (z pustym zapisem), a następnie po prostu zignorowałem zgłoszony wyjątek. Wydaje się, że jest to niewłaściwe, ale wydaje się, że nie ma żadnych złych skutków (przynajmniej dla tego, co robię później, czyli rozpoczęcia innej aktywności przechodzącej w wyniku mojego długiego zapytania jako Extra)
źródło
Activity
ma odniesienie doDialog
. Po zmianie konfiguracji pierwszaActivity
jest niszczona, co oznacza, że wszystkie pola są ustawione nanull
. Ale niski poziomWindowManager
ma również odniesienie doDialog
(ponieważ nie został jeszcze odrzucony). NowyActivity
próbuje utworzyć nowyDialog
(wpreExecute()
), a menedżer okien zgłasza krytyczny wyjątek, który ci to uniemożliwia. Rzeczywiście, jeśli to zrobi, nie byłoby sposobu, aby czysto zniszczyćDialog
stąd zachowanie odniesienia do inicjałuActivity
. Czy mam rację?Najprostszym i najbardziej elastycznym rozwiązaniem jest użycie AsyncTask ze statycznym odniesieniem do ProgressBar . Zapewnia to zamknięte, a zatem wielokrotnego użytku rozwiązanie problemów zmiany orientacji. To rozwiązanie dobrze mi służyło do wykonywania różnorodnych zadań asynchronicznych, w tym pobierania Internetu, komunikacji z usługami i skanowania systemu plików. Rozwiązanie zostało dobrze przetestowane na wielu wersjach Androida i modelach telefonów. Kompletne demo można znaleźć tutaj ze szczególnym zainteresowaniem w DownloadFile.java
Przedstawiam poniższe jako przykład koncepcji
Użycie w działaniu na Androida jest proste
źródło
Po zmianie orientacji Android zabija tę aktywność i tworzy nową aktywność. Sugeruję użyć modernizacji z Rx Java. który uchwyt ulega awarii automatycznie.
Skorzystaj z tej metody przy ponownym wywołaniu.
.subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ())
źródło