Moja aktywność próbuje utworzyć AlertDialog, który wymaga kontekstu jako parametru. Działa to zgodnie z oczekiwaniami, jeśli użyję:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Jestem jednak ostrożny w używaniu „tego” jako kontekstu ze względu na możliwość wycieków pamięci, gdy Aktywność zostanie zniszczona i odtworzona nawet podczas czegoś prostego, takiego jak obracanie ekranu. Z pokrewnego postu na blogu programisty Androida :
Istnieją dwa proste sposoby uniknięcia wycieków pamięci kontekstowej. Najbardziej oczywistym z nich jest unikanie ucieczki z kontekstu poza własnym zasięgiem. Powyższy przykład pokazuje przypadek odniesienia statycznego, ale klasy wewnętrzne i ich ukryte odniesienie do klasy zewnętrznej mogą być równie niebezpieczne. Drugim rozwiązaniem jest użycie kontekstu aplikacji. Ten kontekst będzie istniał tak długo, jak długo aplikacja będzie żyła i nie będzie zależeć od cyklu życia działań. Jeśli planujesz zachować obiekty o długiej żywotności, które potrzebują kontekstu, zapamiętaj obiekt aplikacji. Możesz go łatwo uzyskać, wywołując Context.getApplicationContext () lub Activity.getApplication ().
Ale dla AlertDialog()
żadnego z nich getApplicationContext()
lub getApplication()
jest akceptowalny jako kontekst, ponieważ rzuca wyjątek:
„Nie można dodać okna - token null nie jest przeznaczony dla aplikacji”
według referencji: 1 , 2 , 3 itd.
Czy to naprawdę powinno być uważane za „błąd”, skoro oficjalnie zaleca się stosowanie, Activity.getApplication()
a mimo to nie działa tak, jak w reklamie?
Jim
źródło
Odpowiedzi:
Zamiast tego po
getApplicationContext()
prostu użyjActivityName.this
.źródło
Listener
zajęcia są często anonimowo-wewnętrzne, zwykle tak robięfinal Context ctx = this;
i nie ma mnie;)Korzystanie
this
nie działało dla mnie, ale działałoMyActivityName.this
. Mam nadzieję, że pomoże to każdemu, kto nie mógł dostać sięthis
do pracy.źródło
this
z wewnętrznej klasy. Jeśli chcesz odwoływać się do wystąpienia klasy zewnętrznej, musisz to określić, tak jak to robiszOuterClass.this
. Tylko użyciethis
zawsze odwołuje się do najbardziej wewnętrznej instancji klasy.Możesz nadal używać
getApplicationContext()
, ale przed użyciem powinieneś dodać tę flagę:,dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
a błąd się nie pojawi.Dodaj następujące pozwolenie do swojego manifestu:
źródło
Prawidłowo zidentyfikowałeś problem, gdy powiedziałeś „... dla AlertDialog () ani getApplicationContext (), ani getApplication () nie są akceptowane jako kontekst, ponieważ zgłasza wyjątek:„ Nie można dodać okna - token null nie jest dla Aplikacja'"
Aby utworzyć okno dialogowe, potrzebujesz kontekstu działania lub kontekstu usługi , a nie kontekstu aplikacji (zarówno getApplicationContext (), jak i getApplication () zwracają kontekst aplikacji).
Oto jak uzyskać kontekst działania :
(1) W działaniu lub usłudze:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
(2) we fragmencie:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Wycieki pamięci nie stanowią problemu nieodłącznie związanego z odniesieniem „to”, które jest odniesieniem obiektu do siebie (tj. Odniesieniem do faktycznej przydzielonej pamięci do przechowywania danych obiektu). Dzieje się tak z każdą przydzieloną pamięcią, dla której Garbage Collector (GC) nie jest w stanie zwolnić po tym, jak przydzielona pamięć przeżyje swój okres użytkowania.
Przez większość czasu, gdy zmienna wykracza poza zakres, pamięć zostanie odzyskana przez GC. Jednak wycieki pamięci mogą wystąpić, gdy odwołanie do obiektu przechowywanego przez zmienną, powiedz „x”, utrzymuje się nawet po upływie okresu użyteczności obiektu. Przydzielona pamięć zostanie zatem utracona, dopóki „x” będzie zawierało odniesienie do niej, ponieważ GC nie zwolni pamięci, dopóki pamięć ta będzie nadal wskazywana. Czasami wycieki pamięci nie są widoczne z powodu łańcucha odniesień do przydzielonej pamięci. W takim przypadku GC nie zwolni pamięci, dopóki wszystkie odniesienia do tej pamięci nie zostaną usunięte.
Aby zapobiec wyciekom pamięci, sprawdź kod pod kątem błędów logicznych, które powodują, że do przydzielonej pamięci odwołuje się w nieskończoność „to” (lub inne odniesienia). Pamiętaj, aby sprawdzić również odniesienia do łańcucha. Oto niektóre narzędzia, których możesz użyć, aby przeanalizować wykorzystanie pamięci i znaleźć te nieznośne wycieki pamięci:
JRockit Mission Control
JProbe
YourKit
AD4J
źródło
Twoje okno dialogowe nie powinno być „długotrwałym obiektem, który potrzebuje kontekstu”. Dokumentacja jest myląca. Zasadniczo, jeśli robisz coś takiego:
(zwróć uwagę na statyczne )
Potem, gdzieś to zrobiłeś
Prawdopodobnie wycieknie pierwotna aktywność podczas rotacji lub podobnej czynności, która mogłaby ją zniszczyć. (Chyba że wyczyścisz w onDestroy, ale w takim przypadku prawdopodobnie nie spowodowałbyś, aby obiekt Dialog był statyczny)
W przypadku niektórych struktur danych sensowne byłoby uczynienie ich statycznymi i opartymi na kontekście aplikacji, ale generalnie nie dla rzeczy związanych z interfejsem użytkownika, takich jak okna dialogowe. Więc coś takiego:
Jest w porządku i nie powinien przeciekać aktywności, ponieważ mDialog zostałby zwolniony z działalnością, ponieważ nie jest statyczny.
źródło
Musiałem wysłać mój kontekst za pomocą konstruktora na niestandardowym adapterze wyświetlanym w fragmencie i miałem ten problem z getApplicationContext (). Rozwiązałem to za pomocą:
this.getActivity().getWindow().getContext()
wonCreate
wywołaniu zwrotnym fragmentów .źródło
w działaniu po prostu użyj:
we fragmencie:
źródło
W
Activity
po kliknięciu przycisku pokazującego okno dialogowePracował dla mnie.
źródło
***** wersja kotlin *****
Powinieneś przekazać
this@YourActivity
zamiastapplicationContext
lubbaseContext
źródło
Trochę Hack: można zapobiec niszczeniu swoją aktywność przez GC (nie powinno się to zrobić, ale może pomóc w niektórych sytuacjach nie zapomnij ustawić.
contextForDialog
Donull
kiedy to już nie jest potrzebne):źródło
Jeśli używasz fragmentu i używasz komunikatu AlertDialog / Toast, użyj getActivity () w parametrze kontekstu.
lubię to
źródło
Wystarczy użyć następujących:
DLA UŻYTKOWNIKÓW JAVA
W przypadku korzystania z aktywności ->
AlertDialog.Builder builder = new AlertDialog.Builder(this);
LUB
AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);
W przypadku korzystania z fragmentu ->
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
DLA UŻYTKOWNIKÓW KOTLIN
W przypadku korzystania z aktywności ->
val builder = AlertDialog.Builder(this)
LUB
val builder = AlertDialog.Builder(this@your_activity.this)
W przypadku korzystania z fragmentu ->
val builder = AlertDialog.Builder(activity!!)
źródło
dodawanie
i
"android.permission.SYSTEM_ALERT_WINDOW"/>
w manifestieTeraz działa dla mnie. Po nawet zamknięciu i otwarciu aplikacji, dał mi wtedy błąd.
źródło
Używałem
ProgressDialog
fragmentu i otrzymywałem ten błąd podczas przekazywaniagetActivity().getApplicationContext()
jako parametru konstruktora. Zmiana gogetActivity().getBaseContext()
również nie działała.Rozwiązaniem, które działało dla mnie, było przejście
getActivity()
; to znaczyprogressDialog = new ProgressDialog(getActivity());
źródło
Posługiwać się
MyDialog md = new MyDialog(MyActivity.this.getParent());
źródło
Jeśli jesteś poza działaniem, musisz użyć w funkcji „NameOfMyActivity.this” jako działania, na przykład:
źródło
Jeśli używasz fragmentu i
AlertDialog / Toast
wiadomości, użyjgetActivity()
w parametrze kontekstu.Pracował dla mnie.
Twoje zdrowie!
źródło
Spróbuj użyć kontekstu działania, które będzie w oknie dialogowym. Należy jednak zachować ostrożność, używając słowa kluczowego „to”, ponieważ nie będzie ono działać za każdym razem.
Na przykład, jeśli masz TabActivity jako host z dwiema kartami, a każda karta jest innym działaniem, a jeśli spróbujesz utworzyć okno dialogowe z jednej z kart (działań) i jeśli użyjesz „tego”, otrzymasz wyjątek, w tym okno dialogowe sprawy powinno być połączone z działaniem hosta, które hostuje wszystko i jest widoczne. (możesz powiedzieć najbardziej widoczny kontekst działania rodzica)
Nie znalazłem tych informacji w żadnym dokumencie, ale próbowałem. To jest moje rozwiązanie bez silnego zaplecza. Jeśli ktoś ma większą wiedzę, nie wahaj się komentować.
źródło
Dla przyszłych czytelników powinno to pomóc:
źródło
W moim przypadku praca:
źródło
Lub inną możliwością jest utworzenie okna dialogowego w następujący sposób:
źródło
Myślę, że może się to zdarzyć, jeśli próbujesz wyświetlić okno dialogowe z wątku, który nie jest głównym wątkiem interfejsu użytkownika.
Użyj
runOnUiThread()
w takim przypadku.źródło
Spróbuj
getParent()
w miejscu argumentu kontekstu, jak nowaAlertDialog.Builder(getParent());
Mam nadzieję, że zadziała, zadziałało dla mnie.źródło
Po przyjrzeniu się interfejsowi API możesz przekazać okno swojej aktywności lub getActivity, jeśli jesteś we fragmencie, a następnie zdecydowanie wyczyść go za pomocą metody dialog.dismiss () w metodach powrotu, aby zapobiec wyciekom.
Chociaż nigdzie nie jest to wyraźnie określone, wydaje się, że przywrócono okno dialogowe OnClickHandlers tylko po to, aby to zrobić.
źródło
Jeśli okno dialogowe tworzy się na adapterze:
Przekaż działanie konstruktorowi adaptera:
Odbierz na adapterze:
Teraz możesz używać w swoim Konstruktorze
źródło
Oto jak rozwiązałem ten sam błąd dla mojej aplikacji:
Dodanie następującego wiersza po utworzeniu okna dialogowego:
Nie musisz pozyskiwać kontekstu. Jest to szczególnie przydatne, jeśli wyskakuje inne okno dialogowe nad bieżącym wyskakującym oknem dialogowym. Lub gdy uzyskanie kontekstu nie jest wygodne.
Mam nadzieję, że pomoże Ci to w rozwoju aplikacji.
David
źródło
źródło