In Entwicklerkonsolen-Fehlerberichten werden manchmal Berichte mit NPE-Problemen angezeigt. Ich verstehe nicht, was mit meinem Code falsch ist. Auf dem Emulator und meiner Geräteanwendung funktioniert es gut ohne Forcecloses. Einige Benutzer erhalten jedoch NullPointerException in der Fragmentklasse, wenn die Methode getActivity () aufgerufen wird.
Aktivität
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) {}
});
}
AsyncTask-Klasse
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Fragmentklasse
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();
...
}
}
Möglicherweise tritt dieser Fehler auf, wenn Anwendungen aus dem Hintergrund fortgesetzt werden. Wie soll ich in diesem Fall richtig mit dieser Situation umgehen?
android
android-fragments
android-activity
android-asynctask
nullpointerexception
Georgy Gobozov
quelle
quelle
Antworten:
Es scheint, dass ich eine Lösung für mein Problem gefunden habe. Hier und hier werden sehr gute Erklärungen gegeben . Hier ist mein Beispiel:
Die Hauptidee in diesem Code ist, dass Sie während der normalen Ausführung Ihrer Anwendung neue Fragmente erstellen und diese an den Adapter übergeben. Wenn Sie fortfahren, verfügt Ihr Anwendungsfragmentmanager bereits über die Instanz dieses Fragments, und Sie müssen es vom Fragmentmanager abrufen und an den Adapter übergeben.
AKTUALISIEREN
Es ist auch eine gute Vorgehensweise, wenn Sie Fragmente verwenden, um isAdded zu überprüfen, bevor getActivity () aufgerufen wird. Dies hilft, eine Nullzeigerausnahme zu vermeiden, wenn das Fragment von der Aktivität getrennt wird. Eine Aktivität kann beispielsweise ein Fragment enthalten, das eine asynchrone Aufgabe überträgt. Wenn die Aufgabe abgeschlossen ist, wird der Listener onTaskComplete aufgerufen.
Wenn wir das Fragment öffnen, eine Aufgabe verschieben und dann schnell zurück drücken, um zu einer vorherigen Aktivität zurückzukehren, wird nach Abschluss der Aufgabe versucht, auf die Aktivität in onPostExecute () zuzugreifen, indem die Methode getActivity () aufgerufen wird. Wenn die Aktivität bereits getrennt ist und diese Prüfung nicht vorhanden ist:
dann stürzt die Anwendung ab.
quelle
isAdded()
vor jedem Zugriff anrufen zu müssen ... macht den Code hässlich.if(isAdded())
oderif(getActivity() != null)
Ok, ich weiß, dass diese Frage tatsächlich gelöst ist, aber ich habe beschlossen, meine Lösung dafür zu teilen. Ich habe eine abstrakte Elternklasse für Folgendes erstellt
Fragment
:Wie Sie sehen können, habe ich einen Listener hinzugefügt, sodass ich immer dann anrufen muss , wenn ich
Fragments
Activity
anstelle von Standard einen bekommengetActivity()
mussquelle
Das Beste, um dies zu beseitigen, besteht darin, die Aktivitätsreferenz zu behalten, wenn sie
onAttach
aufgerufen wird, und die Aktivitätsreferenz zu verwenden, wo immer dies erforderlich ist, zBearbeitet, da
onAttach(Activity)
abgeschrieben wird & jetztonAttach(Context)
verwendet wirdquelle
getActivity()
null zurückgegeben wird, liegt dies daran, dass Sie sich nicht mehr in einer Aktivität befinden. Dies ist eine schmutzige Problemumgehung.Rufen Sie keine Methoden innerhalb des Fragments auf, für die getActivity () erforderlich ist, bis onStart in der übergeordneten Aktivität.
quelle
Ich habe eine Weile mit dieser Art von Problem gekämpft und ich denke, ich habe eine zuverlässige Lösung gefunden.
Es ist ziemlich schwierig, sicher zu wissen , dass
this.getActivity()
nicht zurückkehren wirdnull
für einFragment
, vor allem , wenn Sie mit jeder Art von Netzwerkverhalten zu tun haben , die Ihrem Code genügend Zeit gibt zurückzuziehenActivity
Referenzen.In der folgenden Lösung deklariere ich eine kleine Verwaltungsklasse namens
ActivityBuffer
. Im Wesentlichen geht es hierclass
darum, eine zuverlässige Referenz auf einen Eigentümer zu erhaltenActivity
und zu versprechen,Runnable
s in einem gültigenActivity
Kontext auszuführen, wenn eine gültige Referenz verfügbar ist. DieRunnable
s werden sofort auf dem UI-Thread ausgeführt, wenn sieContext
verfügbar sind. Andernfalls wird die Ausführung verschoben, bis sieContext
fertig sind.In Bezug auf die Implementierung müssen wir darauf achten, dass die Lebenszyklusmethoden so angewendet werden, dass sie mit dem oben von Pawan M beschriebenen Verhalten übereinstimmen :
Schließlich können Sie in allen Bereichen in Ihrem Bereich
Fragment
, inBaseFragment
denen Sie in Bezug auf einen Anruf nicht vertrauenswürdig sindgetActivity()
, einfach einen Anruf tätigenthis.getActivityBuffer().safely(...)
und einenActivityBuffer.IRunnable
für die Aufgabe deklarieren !Der Inhalt von
void run(final Activity pActivity)
wird dann garantiert entlang des UI-Threads ausgeführt.Das
ActivityBuffer
kann dann wie folgt verwendet werden:quelle
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich denke, ich muss meine Antwort darauf geben, weil mein Problem nicht von anderen gelöst wurde.
Zunächst einmal: Ich habe Fragmente mithilfe von fragmentTransactions dynamisch hinzugefügt. Zweitens: Meine Fragmente wurden mithilfe von AsyncTasks (DB-Abfragen auf einem Server) geändert. Drittens: Mein Fragment wurde beim Aktivitätsstart nicht instanziiert. Viertens: Ich habe eine benutzerdefinierte Fragmentinstanziierung "Erstellen oder Laden" verwendet, um die Fragmentvariable abzurufen. Viertens: Die Aktivität wurde aufgrund einer Orientierungsänderung neu erstellt
Das Problem war, dass ich das Fragment wegen der Abfrageantwort "entfernen" wollte, aber das Fragment wurde kurz zuvor falsch erstellt. Ich weiß nicht, warum das Fragment, wahrscheinlich weil das "Commit" später durchgeführt wird, noch nicht hinzugefügt wurde, als es Zeit war, es zu entfernen. Daher gab getActivity () null zurück.
Lösung: 1) Ich musste überprüfen, ob ich richtig versucht habe, die erste Instanz des Fragments zu finden, bevor ich eine neue erstellte. 2) Ich musste serRetainInstance (true) auf dieses Fragment setzen, um es durch Orientierungsänderungen zu erhalten (kein Backstack) benötigt daher kein Problem) 3) Anstatt "altes Fragment neu zu erstellen oder abzurufen" kurz vor "entfernen", setze ich das Fragment direkt auf Aktivitätsstart. Das Instanziieren beim Aktivitätsstart anstelle des "Ladens" (oder Instanziierens) der Fragmentvariablen vor dem Entfernen verhinderte Probleme mit getActivity.
quelle
In Kotlin können Sie auf diese Weise versuchen, die Nullbedingung getActivity () zu behandeln.
Es wird überprüft, ob die Aktivität null ist oder nicht. Wenn nicht null, wird der innere Code ausgeführt.
quelle