[android] getActivity () renvoie null dans la fonction Fragment



Answers

Le mieux pour s'en débarrasser est de garder une référence d'activité quand onAttach est appelé et d'utiliser la référence d'activité là où c'est nécessaire, par exemple

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

@Override
public void onDetach() {
    super.onDetach();
    mContext = null;
}
Question

J'ai un fragment (F1) avec une méthode publique comme ça

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

et oui quand je l'appelle (de l'Activité), c'est nul ...

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

Ce doit être quelque chose que je fais très mal, mais je ne sais pas ce que c'est




J'utilise OkHttp et je viens de faire face à ce problème.

Pour la première partie, @thucnguyen était sur la bonne voie .

Cela s'est produit lorsque vous appelez getActivity () dans un autre thread qui s'est terminé après la suppression du fragment. Le cas typique consiste à appeler getActivity () (par exemple pour un Toast) lorsqu'une requête HTTP est terminée (dans onResponse par exemple).

Certains appels HTTP étaient en cours d'exécution même après la fermeture de l'activité (car le traitement d'une requête HTTP peut prendre un certain temps). J'ai ensuite, à travers le HttpCallback essayé de mettre à jour certains champs Fragment et obtenu une exception null en essayant de getActivity() .

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

IMO la solution est d' empêcher les rappels de se produire lorsque le fragment n'est plus en vie (et ce n'est pas seulement avec Okhttp).

Le correctif: Prévention.

Si vous regardez le cycle de vie des fragments (plus d'infos here ), vous remarquerez qu'il existe des onAttach(Context context) et onDetach() . Ceux-ci sont appelés après que le fragment appartient à une activité et juste avant d'arrêter de l'être respectivement.

Cela signifie que nous pouvons empêcher ce rappel de se produire en le contrôlant dans la méthode 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();
    }
}



Depuis le niveau d'API Android 23, onAttach (activité d'activité) est obsolète. Vous devez utiliser onAttach (Context context). http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

L'activité est un contexte, donc si vous pouvez simplement vérifier que le contexte est une activité, lancez-la si nécessaire.

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

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}



L'ordre dans lequel les rappels sont appelés après commit ():

  1. Quelle que soit la méthode que vous appelez manuellement juste après commit ()
  2. onAttach ()
  3. onCreateView ()
  4. onActivityCreated ()

J'avais besoin de faire un travail qui impliquait certaines vues, donc onAttach () ne fonctionnait pas pour moi; il s'est écrasé. J'ai donc déplacé une partie de mon code qui définissait des paramètres dans une méthode appelée juste après commit () (1.), puis l'autre partie du code qui traitait la vue dans onCreateView () (3.).




Vous pouvez utiliser onAttach ou si vous ne voulez pas mettre onAttach partout, vous pouvez mettre une méthode qui retourne ApplicationContext sur la classe App principale:

public class App {
    ...  
    private static Context context;

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

    public static Context getContext() {
        return context;
    }
    ...
}

Après cela, vous pouvez le réutiliser partout dans votre projet, comme ceci:

App.getContext().getString(id)

S'il vous plaît laissez-moi savoir si cela ne fonctionne pas pour vous.




Faites comme suit. Je pense que cela vous sera utile.

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

}



Related