Je reçois rarement cette erreur en effectuant un appel API.
Java.lang.IllegalStateException: Fragment not attached to Activity
J'ai essayé de mettre le code dans la méthode isAdded()
pour vérifier si fragment est actuellement ajouté à son activité, mais j'obtiens rarement cette erreur. Je ne comprends pas pourquoi je reçois toujours cette erreur. Comment puis-je l'empêcher?
Son erreur montrant sur la ligne
cameraInfo.setId(getResources().getString(R.string.camera_id));
Vous trouverez ci-dessous l'exemple d'appel d'api que je fais.
SAPI.getInfo(getActivity(),
new APIResponseListener() {
@Override
public void onResponse(Object response) {
cameraInfo = new SInfo();
if(isAdded()) {
cameraInfo.setId(getResources().getString(R.string.camera_id));
cameraInfo.setName(getResources().getString(R.string.camera_name));
cameraInfo.setColor(getResources().getString(R.string.camera_color));
cameraInfo.setEnabled(true);
}
}
@Override
public void onError(VolleyError error) {
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
}
}
});
Cette erreur est due à l’effet combiné de deux facteurs:
onResponse()
, soit onError()
(qui fonctionne sur le thread principal) sans savoir si la Activity
est toujours au premier plan ou non. Si la Activity
a disparu (l'utilisateur a navigué ailleurs), getActivity()
renvoie null.Response
est exprimé en tant que classe interne anonyme, qui contient implicitement une forte référence à la classe Activity
externe. Cela entraîne une fuite de mémoire classique.Pour résoudre ce problème, vous devriez toujours faire:
Activity activity = getActivity();
if(activity != null){
// etc ...
}
et aussi, utilisez isAdded()
dans la méthode onError()
:
@Override
public void onError(VolleyError error) {
Activity activity = getActivity();
if(activity != null && isAdded())
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
}
}
}
Le cycle de vie des fragments est très complexe et plein de bugs, essayez d'ajouter:
Activity activity = getActivity();
if (isAdded() && activity != null) {
...
}
J'ai trouvé une solution très simple La méthode isAdded () est l'une des méthodes de fragment permettant d'identifier si ce fragment en cours est lié à son activité ou non.
nous pouvons utiliser cela comme partout dans la classe de fragments comme:
if(isAdded())
{
// using this method, we can do whatever we want which will prevent **Java.lang.IllegalStateException: Fragment not attached to Activity** exception.
}
Exception: Java.lang.IllegalStateException: Fragment
DeadlineListFragment {ad2ef970} non attaché à l'activité
Catégorie: Cycle de vie
Description : Lorsque vous effectuez des opérations fastidieuses dans le thread d'arrière-plan (AsyncTask, par exemple), un nouveau fragment a été créé entre-temps et a été détaché de l'activité avant la fin du thread d'arrière-plan. Le code dans le thread d'interface utilisateur (par exemple, onPostExecute) appelle un fragment séparé en lançant une telle exception.
Solution fixe:
Annulez le fil d’arrière-plan lorsque vous mettez en pause ou arrêtez le fragment
Utilisez isAdded () pour vérifier si le fragment est attaché , Puis pour getResources () à partir d'activité.
il se peut que je sois en retard, mais que je puisse aider quelqu'un ..... La meilleure solution consiste à créer une instance de classe d'application globale et à l'appeler dans le fragment particulier où votre activité n'est pas attachée.
comme ci-dessous
icon = MyApplication.getInstance().getString(R.string.weather_thunder);
Voici la classe d'application
public class MyApplication extends Application {
private static MyApplication mInstance;
private RequestQueue mRequestQueue;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
}
Cette erreur peut survenir si vous instanciez un fragment impossible à instancier:
Fragment myFragment = MyFragment.NewInstance();
public classs MyFragment extends Fragment {
public void onCreate() {
// Some error here, or anywhere inside the class is preventing it from being instantiated
}
}
Dans mon cas, j'ai rencontré ceci quand j'ai essayé d'utiliser:
private String loading = getString(R.string.loading);
Dans Fragment, utilisez isAdded()
Il retournera la valeur true si le fragment est actuellement lié à Activity.
Si vous voulez vérifier à l'intérieur de l'activité
Fragment fragment = new MyFragment();
if(fragment.getActivity()!=null)
{ // your code here}
else{
//do something
}
J'espère que ça va aider quelqu'un
J'ai adopté l'approche suivante pour traiter ce problème. Création d'une nouvelle classe qui agit comme un wrapper pour les méthodes d'activité comme celle-ci
public class ContextWrapper {
public static String getString(Activity activity, int resourceId, String defaultValue) {
if (activity != null) {
return activity.getString(resourceId);
} else {
return defaultValue;
}
}
//similar methods like getDrawable(), getResources() etc
}
Maintenant, chaque fois que j'ai besoin d'accéder à des ressources de fragments ou d'activités, au lieu d'appeler directement la méthode, j'utilise cette classe. Si l'activité context
n'est pas null
, elle retourne la valeur de l'actif et si context
est null, elle transmet une valeur par défaut (qui est également spécifiée par l'appelant de la fonction).
Important Ce n'est pas une solution, c'est un moyen efficace de gérer ce crash avec élégance. Vous voudriez ajouter des journaux dans les cas où vous obtenez l'instance d'activité avec la valeur null et essayer de résoudre ce problème, si possible.
Ce problème se produit chaque fois que vous appelez un contexte indisponible ou nul lorsque vous l'appelez. Cela peut se produire lorsque vous appelez le contexte du fil d'activité principal sur un fil en arrière-plan ou le contexte du fil en arrière-plan sur le fil d'activité principal.
Par exemple, j'ai mis à jour ma chaîne de préférence partagée comme suit.
editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();
Et appelé finish () juste après. Maintenant, ce qui se passe, c'est que commit est exécuté sur le thread principal et arrête tout autre engagement Async s'il arrive jusqu'à ce qu'il se termine. Donc, son contexte est actif jusqu'à ce que l'écriture soit terminée. Par conséquent, le contexte précédent est actif, ce qui provoque l'erreur.
Assurez-vous donc que votre code soit revérifié s’il existe un code présentant ce problème de contexte.
Parfois, cette exception est provoquée par un bogue dans l’implémentation de la bibliothèque de support. Récemment, j'ai dû rétrograder de 26.1.0 à 25.4.0 pour m'en débarrasser.
cela se produit lorsque le fragment n'a pas de contexte; la méthode getActivity () renvoie donc la valeur null. Vérifiez si vous utilisez le contexte avant de l’obtenir , ou si l’activité n’existe plus. utilisez le contexte dans fragment.onCreate et après la réponse de l'API généralement ce problème