Pobieram niektóre dane z Internetu w wątku w tle (używam AsyncTask
) i wyświetlam okno dialogowe postępu podczas pobierania. Zmienia się orientacja, działanie jest ponownie uruchamiane, a następnie moja AsyncTask jest zakończona - chcę zamknąć okno dialogowe postępu i rozpocząć nowe działanie. Ale wywoływanie funkcjiISSUTDialog czasami generuje wyjątek (prawdopodobnie dlatego, że działanie zostało zniszczone, a nowe działanie jeszcze się nie rozpoczęło).
Jaki jest najlepszy sposób poradzenia sobie z tego rodzaju problemem (aktualizacja interfejsu użytkownika z wątku w tle, który działa, nawet jeśli użytkownik zmieni orientację)? Czy ktoś z Google przedstawił jakieś „oficjalne rozwiązanie”?
Odpowiedzi:
Krok 1: Sprawdź swoją
AsyncTask
dostatic
zagnieżdżone klasy lub całkowicie odrębną klasę, tylko nie wewnętrzną (non-statycznego zagnieżdżone) klasę.Krok # 2:
AsyncTask
PrzytrzymajActivity
element danych za pomocą konstruktora i setera.Krok # 3: Podczas tworzenia
AsyncTask
podaj prądActivity
do konstruktora.Krok # 4:
onRetainNonConfigurationInstance()
WróćAsyncTask
, po odłączeniu go od oryginalnej, już nieobecnej aktywności.Krok # 5:
onCreate()
JeśligetLastNonConfigurationInstance()
tak nie jestnull
, rzuć go na swojąAsyncTask
klasę i zadzwoń do setera, aby powiązał nową aktywność z zadaniem.Krok # 6: Nie odnosić się do członka danych aktywności z
doInBackground()
.Jeśli zastosujesz się do powyższego przepisu, wszystko zadziała.
onProgressUpdate()
ionPostExecute()
są zawieszone między początkiemonRetainNonConfigurationInstance()
a końcem kolejnegoonCreate()
.Oto przykładowy projekt demonstrujący technikę.
Innym podejściem jest porzucenie
AsyncTask
i przeniesienie pracy doIntentService
. Jest to szczególnie przydatne, jeśli praca do wykonania może być długa i powinna trwać bez względu na to, co użytkownik robi w zakresie działań (np. Pobieranie dużego pliku). Możesz użyć uporządkowanej transmisji,Intent
aby albo aktywność reagowała na wykonywaną pracę (jeśli nadal jest na pierwszym planie), albo podnieść a,Notification
aby poinformować użytkownika, czy praca została wykonana. Oto post na blogu zawierający więcej informacji na temat tego wzoru.źródło
onRetainNonConfigurationInstance()
jest przestarzałe, a sugerowaną alternatywą jest użyciesetRetainInstance()
, ale nie zwraca obiektu. Czy można obsługiwaćasyncTask
zmiany konfiguracjisetRetainInstance()
?Fragment
przytrzymaćAsyncTask
. MiejFragment
wezwaniesetRetainInstance(true)
na siebie. PorozmawiajAsyncTask
tylko zFragment
. Teraz, po zmianie konfiguracji,Fragment
nie jest niszczony i odtwarzany (nawet jeśli działanie jest), a więcAsyncTask
jest zachowywany przez zmianę konfiguracji.Przyjęta odpowiedź była bardzo pomocna, ale nie ma okna dialogowego postępu.
Na szczęście dla ciebie, czytelniku, stworzyłem niezwykle obszerny i działający przykład AsyncTask z oknem postępu !
źródło
Pracowałem przez tydzień, aby znaleźć rozwiązanie tego dylematu, bez uciekania się do edycji pliku manifestu. Założenia tego rozwiązania są następujące:
Realizacja
Musisz skopiować dwa pliki znajdujące się na dole tego postu do swojego obszaru roboczego. Upewnij się tylko, że:
Wszystkie twoje
Activity
powinny się przedłużyćBaseActivity
W
onCreate()
,super.onCreate()
powinien być nazywany po zainicjować żadnych elementów, które muszą być dostępne przez twojeASyncTask
s. Zastąp także,getContentViewId()
aby podać identyfikator układu formularza.Zastąp
onCreateDialog()
jak zwykle, aby utworzyć okna dialogowe zarządzane przez działanie.Zobacz kod poniżej przykładowej statycznej klasy wewnętrznej, aby Twoje AsyncTasks. Możesz zapisać swój wynik w mResult, aby uzyskać do niego dostęp później.
I wreszcie, aby uruchomić nowe zadanie:
Otóż to! Mam nadzieję, że to solidne rozwiązanie pomoże komuś.
BaseActivity.java (sam organizuj import)
SuperAsyncTask.java
źródło
Tak.
Rozwiązaniem jest raczej propozycja architektury aplikacji niż tylko trochę kodu .
Zaproponowali 3 wzorce projektowe, które pozwalają aplikacji na synchronizację z serwerem, niezależnie od stanu aplikacji (zadziała nawet, jeśli użytkownik zakończy aplikację, użytkownik zmieni ekran, aplikacja zostanie zakończona, co drugi możliwy stan, w którym operacja danych w tle może zostać naruszona, obejmuje to)
Propozycję wyjaśniono w wystąpieniu aplikacji klienckich REST dla systemu Android podczas Google I / O 2010 autorstwa Virgila Dobjanschi. Ma 1 godzinę, ale bardzo warto go obejrzeć.
Podstawą jest wyodrębnienie operacji sieciowych do działania,
Service
które działa niezależnie od dowolnejActivity
aplikacji. Jeśli pracujesz z bazami danych, stosowanieContentResolver
iCursor
nie daje out-of-the-box wzorca Obserwator , który jest wygodny do aktualizacji UI bez aditional logiki, po zaktualizowaniu lokalną bazę danych z pobranego danych zdalnych. Każdy inny kod po operacji byłby uruchamiany przez wywołanie zwrotne przekazywane doService
(używamResultReceiver
do tego podklasy).W każdym razie moje wyjaśnienie jest dość niejasne, zdecydowanie powinieneś obejrzeć mowę.
źródło
Chociaż odpowiedź Marka (CommonsWare) rzeczywiście działa na zmiany orientacji, nie powiedzie się, jeśli Aktywność zostanie zniszczona bezpośrednio (jak w przypadku rozmowy telefonicznej).
Możesz obsługiwać zmiany orientacji ORAZ rzadkie zniszczone zdarzenia Activity, używając obiektu Application do odwołania się do ASyncTask.
Jest to doskonałe wyjaśnienie problemu i rozwiązania tutaj :
Podziękowania należą się całkowicie Ryanowi za wymyślenie tego.
źródło
Po 4 latach Google rozwiązało problem, wywołując setRetainInstance (true) w Activity onCreate. Pozwoli to zachować instancję aktywności podczas obracania urządzenia. Mam również proste rozwiązanie dla starszego Androida.
źródło
powinieneś wywoływać wszystkie akcje aktywności za pomocą modułu obsługi aktywności. Więc jeśli jesteś w jakimś wątku, powinieneś utworzyć Runnable i opublikować go za pomocą Handler Activitie. W przeciwnym razie twoja aplikacja ulegnie awarii czasami ze śmiertelnym wyjątkiem.
źródło
To jest moje rozwiązanie: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Zasadniczo kroki są następujące:
onSaveInstanceState
do zapisania zadania, jeśli jest ono nadal przetwarzane.onCreate
dostaję zadanie, jeśli został zapisany.onPause
Odrzucam,ProgressDialog
jeśli to jest pokazane.onResume
Pokaż,ProgressDialog
jeśli zadanie jest nadal przetwarzane.źródło