getActivity () gibt in der Fragment-function null zurück

Ich habe ein Fragment (F1) mit einer öffentlichen Methode wie folgt

public void asd() { if (getActivity() == null) { Log.d("yes","it is null"); } } 

und ja wenn ich es anrufe (von der Activity), ist es null …

 FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction(); F1 f1 = new F1(); transaction1.replace(R.id.upperPart, f1); transaction1.commit(); f1.asd(); 

Es muss etwas sein, was ich falsch mache, aber ich weiß nicht, was das ist

   

commit terminiert die Transaktion, dh es passiert nicht sofort, sondern wird als Arbeit am Hauptthread geplant, wenn der Hauptthread das nächste Mal fertig ist.

Ich würde vorschlagen, ein hinzuzufügen

 onAttach(Activity activity) 

Methode zu Ihrem Fragment und setzen Sie einen Unterbrechungspunkt darauf und sehen, wenn es relativ zu Ihrem Aufruf von asd() aufgerufen wird. Sie werden sehen, dass es nach der Methode aufgerufen wird, bei der Sie den Aufruf von asd() beenden. Der Aufruf onAttach ist der Ort, an dem das Fragment an seine Aktivität angehängt ist, und ab diesem Zeitpunkt gibt getActivity() einen onDetach() ungleich null zurück (nb gibt es auch einen Aufruf onDetach() ).

Das Beste, um dies zu vermeiden, ist, die Aktivitätsreferenz zu behalten, wenn onAttach aufgerufen wird, und die Aktivitätsreferenz zu verwenden, wo immer sie benötigt wird, z

 @Override public void onAttach(Context context) { super.onAttach(activity); mContext = context; } @Override public void onDetach() { super.onDetach(); mContext = null; } 

Dies ist der getActivity() wenn Sie getActivity() in einem anderen Thread aufrufen, der beendet wurde, nachdem das Fragment entfernt wurde. Der typische Fall ist der Aufruf von getActivity() (zB für einen Toast ), wenn eine HTTP-Anfrage beendet wurde ( onResponse in onResponse ).

Um dies zu vermeiden, können Sie den Feldnamen mActivity und anstelle von getActivity() . Dieses Feld kann in der onAttach () – Methode von Fragment wie folgt initialisiert werden:

 @Override public void onAttach(Activity activity) { super.onAttach(activity); mActivity = activity; } 

In meinen Projekten definiere ich normalerweise eine Basisklasse für alle meine Fragmente mit dieser function:

 public abstract class BaseFragment extends Fragment { protected FragmentActivity mActivity; @Override public void onAttach(Activity activity) { super.onAttach(activity); mActivity = (FragmentActivity) activity; } } 

Glückliche Codierung,

Seit Android-API-Stufe 23 ist onAttach (Aktivität Aktivität) veraltet. Sie müssen onAttach (Kontext Kontext) verwenden. http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

Aktivität ist ein Kontext. Wenn Sie also einfach den Kontext überprüfen können, handelt es sich um eine Aktivität, und Sie können sie bei Bedarf umwandeln.

 @Override public void onAttach(Context context) { super.onAttach(context); Activity a; if (context instanceof Activity){ a=(Activity) context; } } 

PJL hat Recht. Ich habe seinen Vorschlag benutzt und das habe ich getan:

  1. definierte globale Variablen für Fragment:

    private final Object attachingActivityLock = new Object();

    private boolean syncVariable = false;

  2. implementiert

 @Override public void onAttach(Activity activity) { super.onAttach(activity); synchronized (attachingActivityLock) { syncVariable = true; attachingActivityLock.notifyAll(); } } 

3 . Ich habe meine function, wo ich getActivity () aufrufen muss, in thread eingepackt, denn wenn sie auf dem Hauptthread ausgeführt würde, würde ich den Thread mit Schritt 4 blockieren und onAttach () würde nie aufgerufen werden.

  Thread processImage = new Thread(new Runnable() { @Override public void run() { processImage(); } }); processImage.start(); 

4. in meiner function, wo ich getActivity () aufrufen muss, benutze ich dies (vor dem Aufruf getActivity ())

  synchronized (attachingActivityLock) { while(!syncVariable){ try { attachingActivityLock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

Wenn Sie einige UI-Updates haben, denken Sie daran, sie im UI-Thread auszuführen. Ich muss ImgeView aktualisieren, also tat ich:

 image.post(new Runnable() { @Override public void run() { image.setImageBitmap(imageToShow); } }); 

Die Reihenfolge, in der die Callbacks nach commit () aufgerufen werden:

  1. Welche Methode Sie auch direkt nach commit () manuell aufrufen
  2. onAttach ()
  3. onCreateView ()
  4. onActivityCreated ()

Ich musste etwas arbeiten, das einige Views involvierte, also funktionierte onAttach () nicht für mich; es ist abgestürzt. Also habe ich einen Teil meines Codes verschoben, der einige Parameter innerhalb einer Methode namens right nach commit () (1.) gesetzt hat, dann den anderen Teil des Codes, der in onCreateView () (3.) behandelt wurde.

Die anderen Antworten, die darauf hinweisen, einen Verweis auf die Aktivität in onAttach beizubehalten, sind nur ein Hinweis auf ein echtes Problem. Wenn getActivity null zurückgibt, bedeutet dies, dass das Fragment nicht an die Aktivität angehängt ist. Am häufigsten tritt dies auf, wenn die Aktivität aufgrund der Rotation oder der Beendigung der Aktivität verloren gegangen ist, das Fragment jedoch eine Art Callback-Listener hat. Wenn der Listener angerufen wird, wenn Sie etwas mit der Aktivität machen müssen, aber die Aktivität weg ist, können Sie nicht viel tun. In Ihrem Code sollten Sie getActivity() != null überprüfen und wenn es nicht da ist, dann tun Sie nichts. Wenn Sie einen Verweis auf die Aktivität beibehalten, die nicht mehr aktiv ist, verhindern Sie, dass die Aktivität als Garbage Collection erfasst wird. Alle UI-Aktionen, die Sie möglicherweise versuchen, werden vom Benutzer nicht gesehen. Ich kann mir Situationen vorstellen, in denen Sie im Callback-Listener einen Kontext für etwas haben möchten, das nicht mit der Benutzeroberfläche zusammenhängt. In diesen Fällen ist es wahrscheinlich sinnvoller, den Anwendungskontext zu erhalten. Beachten Sie, dass der einzige Grund dafür, dass der onAttach Trick kein großer Speicherverlust ist, darin besteht, dass er normalerweise nach dem onAttach des Callback-Listeners nicht mehr benötigt wird und zusammen mit dem Fragment, all seinen Ansichten und dem Aktivitätskontext gesammelt werden kann. Wenn Sie setRetainInstance(true) besteht eine größere Chance auf ein Speicherleck, da das Feld Activity ebenfalls beibehalten wird. Nach der Rotation könnte dies jedoch die vorherige Activity sein und nicht die aktuelle Activity.

Tun Sie wie folgt. Ich denke, es wird dir hilfreich sein.

 private boolean isVisibleToUser = false; private boolean isExecutedOnce = false; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_my, container, false); if (isVisibleToUser && !isExecutedOnce) { executeWithActivity(getActivity()); } return root; } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); this.isVisibleToUser = isVisibleToUser; if (isVisibleToUser && getActivity()!=null) { isExecutedOnce =true; executeWithActivity(getActivity()); } } private void executeWithActivity(Activity activity){ //Do what you have to do when page is loaded with activity } 

Wo nennst du diese function? Wenn Sie es im Konstruktor von Fragment aufrufen, gibt es null .

Rufen getActivity() einfach getActivity() wenn die Methode onCreateView() ausgeführt wird.

Ich benutze OkHttp und ich habe gerade mit diesem Problem konfrontiert.


Für den ersten Teil war @thucnguyen auf dem richtigen Weg .

Dies ist der Fall, wenn Sie getActivity () in einem anderen Thread aufrufen, der beendet wurde, nachdem das Fragment entfernt wurde. Der typische Fall ist der Aufruf von getActivity () (zB für einen Toast), wenn eine HTTP-Anfrage beendet wurde (zB in onResponse).

Einige HTTP-Aufrufe wurden ausgeführt, auch nachdem die Aktivität geschlossen wurde (weil es eine Weile dauern kann, bis eine HTTP-Anforderung abgeschlossen ist). Ich habe dann versucht, durch die HttpCallback einige Fragmente Felder zu aktualisieren und bekam eine null Ausnahme beim Versuch, getActivity() .

 http.newCall(request).enqueue(new Callback(... onResponse(Call call, Response response) { ... getActivity().runOnUiThread(...) // < -- getActivity() was null when it had been destroyed already 

IMO die Lösung ist Callbacks zu verhindern, wenn das Fragment nicht mehr am Leben ist (und das ist nicht nur mit Okhttp).

Die Lösung: Prävention.

Wenn Sie sich den Fragment-Lebenszyklus anschauen (mehr Informationen hier ), werden Sie feststellen, dass es die onAttach(Context context) und onDetach() gibt. Diese werden aufgerufen, nachdem das Fragment zu einer Aktivität gehört und kurz davor stehen bleibt.

Das bedeutet, dass wir diesen callback verhindern können, indem wir ihn in der onDetach Methode onDetach .

 @Override public void onAttach(Context context) { super.onAttach(context); // Initialize HTTP we're going to use later. http = new OkHttpClient.Builder().build(); } @Override public void onDetach() { super.onDetach(); // We don't want to receive any more information about the current HTTP calls after this point. // With Okhttp we can simply cancel the on-going ones (credits to https://github.com/square/okhttp/issues/2205#issuecomment-169363942). for (Call call : http.dispatcher().queuedCalls()) { call.cancel(); } for (Call call : http.dispatcher().runningCalls()) { call.cancel(); } } 

Diejenigen, die immer noch das Problem mit onAttach (Activity activity) haben, haben es gerade in Context geändert –

  @Override public void onAttach(Context context) { super.onAttach(context); this.context = context; } 

In den meisten Fällen reicht das Speichern des Kontexts für Sie aus – wenn Sie beispielsweise getResources () ausführen möchten, können Sie dies direkt aus dem Kontext tun. Wenn Sie den Kontext noch in Ihre Aktivität aufnehmen müssen, tun Sie dies –

  @Override public void onAttach(Context context) { super.onAttach(context); mActivity a; //Your activity class - will probably be a global var. if (context instanceof mActivity){ a=(mActivity) context; } } 

Wie von user1868713 vorgeschlagen.

Sie können onAttach verwenden oder wenn Sie nicht möchten, dass Attach überall eingefügt wird, können Sie eine Methode einfügen, die ApplicationContext in der App-Hauptklasse zurückgibt:

 public class App { ... private static Context context; @Override public void onCreate() { super.onCreate(); context = this; } public static Context getContext() { return context; } ... } 

Danach können Sie es überall in Ihrem Projekt wiederverwenden, so:

 App.getContext().getString(id) 

Bitte lassen Sie mich wissen, ob das für Sie nicht funktioniert.

Bester und solider Weg:

 FragmentActivity activity = (FragmentActivity) getActivity(); activity.finish();