W raportach błędów konsoli programisty czasami widzę raporty z problemem NPE. Nie rozumiem, co jest nie tak z moim kodem. Na emulatorze i mojej aplikacji urządzenia działa dobrze bez forcecloses, jednak niektórzy użytkownicy otrzymują NullPointerException w klasie fragmentów, gdy wywoływana jest metoda getActivity ().
Czynność
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
Klasa AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Klasa fragmentów
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
Być może ten błąd występuje, gdy aplikacje są wznawiane z tła. W takim przypadku, jak powinienem właściwie poradzić sobie z tą sytuacją?
android
android-fragments
android-activity
android-asynctask
nullpointerexception
Georgy Gobozov
źródło
źródło
Odpowiedzi:
Wygląda na to, że znalazłem rozwiązanie mojego problemu. Tu i tutaj podano bardzo dobre wyjaśnienia . Oto mój przykład:
Główną ideą tego kodu jest to, że podczas normalnego działania aplikacji tworzysz nowe fragmenty i przekazujesz je do adaptera. Gdy wznawiasz, menedżer fragmentów aplikacji ma już instancję tego fragmentu i musisz go pobrać z menedżera fragmentów i przekazać go do adaptera.
AKTUALIZACJA
Dobrą praktyką jest także używanie fragmentów do sprawdzania isAdded przed wywołaniem getActivity (). Pomaga to uniknąć wyjątku wskaźnika zerowego, gdy fragment jest odłączony od działania. Na przykład działanie może zawierać fragment, który wypycha zadanie asynchroniczne. Po zakończeniu zadania wywoływany jest detektor onTaskComplete.
Jeśli otworzymy fragment, wypchniemy zadanie, a następnie szybko wrócimy do poprzedniego działania, po zakończeniu zadania spróbuje uzyskać dostęp do działania w onPostExecute (), wywołując metodę getActivity (). Jeśli działanie jest już odłączone, a tego sprawdzenia nie ma:
następnie aplikacja ulega awarii.
źródło
isAdded()
przed każdym dostępem ... sprawia, że kod jest brzydki.if(isAdded())
lubif(getActivity() != null)
Ok, wiem, że to pytanie zostało rozwiązane, ale postanowiłem podzielić się z tym moim rozwiązaniem. Stworzyłem abstrakcyjną klasę nadrzędną dla mojego
Fragment
:Jak widzisz, dodałem detektora, więc za każdym razem, gdy będę musiał uzyskać
Fragments
Activity
zamiast standardowegogetActivity()
, będę musiał zadzwonićźródło
Najlepszym sposobem na pozbycie się tego jest zachowanie odwołania do aktywności, gdy
onAttach
jest wywoływane, i używanie odwołania do aktywności tam, gdzie jest to potrzebne, na przykładEdytowane, ponieważ
onAttach(Activity)
jest amortyzowane i terazonAttach(Context)
jest używaneźródło
getActivity()
zwraca null, oznacza to, że nie jesteś już w aktywności. To jest brudne obejście.Nie należy wywoływać metod w ramach fragmentu, które wymagają getActivity (), dopóki onStart w działaniu nadrzędnym.
źródło
Od pewnego czasu zmagam się z tego rodzaju problemami i wydaje mi się, że wpadłem na niezawodne rozwiązanie.
Jest to dość trudne wiedzieć na pewno, że
this.getActivity()
nie ma powrotunull
dlaFragment
, zwłaszcza jeśli mamy do czynienia z wszelkiego rodzaju zachowania sieci, która daje kod wystarczająco dużo czasu, aby wycofaćActivity
referencje.W poniższym rozwiązaniu deklaruję małą klasę zarządzania o nazwie
ActivityBuffer
. Zasadniczoclass
dotyczy to zachowania wiarygodnego odwołania do własnościActivity
i obiecania wykonaniaRunnable
s we właściwymActivity
kontekście, gdy tylko dostępne jest prawidłowe odwołanie. DoRunnable
s są zaplanowane do wykonania na wątków UI natychmiast, jeśliContext
są dostępne, w przeciwnym razie wykonanie jest odroczone do czasu, żeContext
jest gotowy.Jeśli chodzi o jego realizacji, musimy zadbać, aby zastosować cyklu życia metod w czasie z zachowaniem opisanym powyżej Pawan M :
Wreszcie, we wszystkich obszarach,
Fragment
które rozciągająBaseFragment
się na niewiarygodne połączeniegetActivity()
, po prostu zadzwońthis.getActivityBuffer().safely(...)
i zadeklarujActivityBuffer.IRunnable
zadanie!void run(final Activity pActivity)
Gwarantuje to, że zawartość Twojego pliku zostanie wykonana wzdłuż wątku interfejsu użytkownika.ActivityBuffer
Może być wykorzystywane w następujący sposób:źródło
źródło
Wiem, że to stare pytanie, ale myślę, że muszę udzielić odpowiedzi na to pytanie, ponieważ inni nie rozwiązali mojego problemu.
po pierwsze: dynamicznie dodawałem fragmenty za pomocą fragmentTransactions. Po drugie: moje fragmenty zostały zmodyfikowane za pomocą AsyncTasks (zapytania DB na serwerze). Po trzecie: mój fragment nie został utworzony w momencie rozpoczęcia działania Po czwarte: użyłem niestandardowej instancji fragmentu „utwórz lub załaduj”, aby uzyskać zmienną fragmentu. Po czwarte: aktywność została odtworzona z powodu zmiany orientacji
Problem polegał na tym, że chciałem „usunąć” fragment z powodu odpowiedzi na zapytanie, ale fragment został wcześniej nieprawidłowo utworzony. Nie wiem, dlaczego, prawdopodobnie z powodu „zatwierdzenia”, które zostało wykonane później, fragment nie został jeszcze dodany, kiedy nadszedł czas, aby go usunąć. Dlatego getActivity () zwracał null.
Rozwiązanie: 1) Musiałem sprawdzić, czy poprawnie próbowałem znaleźć pierwszą instancję fragmentu, zanim utworzyłem nowy 2) Musiałem umieścić serRetainInstance (true) na tym fragmencie, aby zachować go poprzez zmianę orientacji (bez backstacka dlatego nie ma problemu) 3) Zamiast „odtworzenia lub odzyskania starego fragmentu” tuż przed „usunięciem”, bezpośrednio włączam fragment na początku aktywności. Tworzenie instancji na początku działania zamiast „ładowania” (lub tworzenia instancji) zmiennej fragmentu przed jej usunięciem zapobiegło problemom z getActivity.
źródło
W Kotlin możesz wypróbować ten sposób do obsługi warunku getActivity () null.
Sprawdzi, czy aktywność jest zerowa, czy nie, a jeśli nie, uruchom kod wewnętrzny.
źródło