java.lang.IllegalStateException: Fragmento no asociado a la Actividad

148

Raramente recibo este error al hacer una llamada a la API.

java.lang.IllegalStateException: Fragment  not attached to Activity

Intenté poner el código dentro del isAdded()método para verificar si el fragmento se agrega actualmente a su actividad, pero todavía rara vez recibo este error. No entiendo por qué sigo recibiendo este error. ¿Como puedo prevenirlo?

Se muestra un error en la línea

cameraInfo.setId(getResources().getString(R.string.camera_id));

A continuación se muestra el ejemplo de llamada API que estoy haciendo.

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();
                        }
                    }
                });
Desarrollador de Android
fuente
cameraInfo.setId (getActivity (). getResources (). getString (R.string.camera_id));
Ashwin H

Respuestas:

203

Este error ocurre debido al efecto combinado de dos factores:

  • La solicitud HTTP, cuando se completa, invoca cualquiera onResponse()o onError()(que funciona en el hilo principal) sin saber si Activitytodavía está en primer plano o no. Si Activitydesapareció (el usuario navegó a otro lugar), getActivity()devuelve nulo.
  • El Volley Responsese expresa como una clase interna anónima, que implícitamente tiene una fuerte referencia a la Activityclase externa . Esto da como resultado una pérdida de memoria clásica.

Para resolver este problema, siempre debe hacer:

Activity activity = getActivity();
if(activity != null){

    // etc ...

}

y también, use isAdded()en el onError()método también:

@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();
        }
    }
}
YS
fuente
2
Cuando se utilizan solicitudes de Volley y AsyncTasks desde dentro de un Activity, no hay una forma infalible de evitar los NPE '. Siempre existe la posibilidad de que el usuario se aleje de la corriente Activitymientras uno de los hilos está haciendo algo en segundo plano, y luego, cuando el hilo se completa onPostExecute()o onResponse()se llama, no hay Activity. Todo lo que puede hacer es verificar las referencias nulas en varios puntos de su código, y eso no es a prueba de balas :)
YS
2
La prueba de mono de Android (adb shell monkey) es realmente buena para eliminar este error si aún no lo ha tenido en cuenta de forma genérica / global.
Groovee60
55
isAdded () es suficiente, boolean público final isAdded () {return mActivity! = null && mAdded; }
lannyf
2
@ruselli: Comprueba la addedbandera booleana y si la Activityinstancia actual es nullo no.
YS
1
@gauravjain Evite realizar solicitudes asincrónicas (como llamadas HTTP) directamente desde Fragmentos. Hazlo desde la Actividad y debería estar bien. Además, borre las referencias de Fragment del FragmentManager, es una buena práctica y es la mejor manera de evitar pérdidas de memoria.
YS
56

El ciclo de vida del fragmento es muy complejo y está lleno de errores, intente agregar:

Activity activity = getActivity(); 
if (isAdded() && activity != null) {
...
}
Miroslav Michalec
fuente
2
¿Dónde debería ponerlo?
Vaclovas Rekašius Jr.
1
@ VaclovasRekašiusJr. Parece prácticamente en cualquier lugar donde desee acceder a la Actividad desde el interior del fragmento. ¡Divertido!
TylerJames
2
¿Qué debo hacer si la actividad == nulo. para mantener viva mi aplicación @Miroslav
pavel
Mire el isAdded (), puede encontrar que "activity! =
Null
@BertKing return mHost != null && mAdded;: eso es lo que hay dentro del método fragment.isAdded (). Pensé que mHost es una actividad si la trazas, pero parece que mHost está dentro de FragmentActivity. Entonces, probablemente, tienes razón. ¿Alguna adición?
Johnny Five
14

Encontré el método isAdded () de Very Very Solution Solution , que es uno de los métodos de fragmentos para identificar que este fragmento actual está conectado a su Actividad o no.

podemos usar esto como en todas partes en la clase de fragmento como:

if(isAdded())
{

// using this method, we can do whatever we want which will prevent   **java.lang.IllegalStateException: Fragment not attached to Activity** exception.

}
Dharmesh Baldha
fuente
12

Excepción: java.lang.IllegalStateException: Fragment

DeadlineListFragment {ad2ef970} no adjunto a la actividad

Categoría: Ciclo de vida

Descripción : al realizar operaciones que requieren mucho tiempo en el subproceso en segundo plano (por ejemplo, AsyncTask), se ha creado un nuevo Fragmento mientras tanto, y se desconectó de la Actividad antes de que finalizara el subproceso en segundo plano. El código en el subproceso de la interfaz de usuario (p. Ej., OnPostExecute) invoca un Fragmento separado y genera dicha excepción.

Solucion de solucion:

  1. Cancele el hilo de fondo al pausar o detener el Fragmento

  2. Use isAdded () para verificar si el fragmento está adjunto y luego obtener getResources () de la actividad.

Rahil Ali
fuente
11

puedo llegar tarde pero ayudar a alguien ..... La mejor solución para esto es crear una instancia de clase de aplicación global y llamarla en el fragmento particular donde no se adjunta su actividad

como abajo

icon = MyApplication.getInstance().getString(R.string.weather_thunder);

Aquí está la clase de aplicación

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;
    }
}
md gouse
fuente
1
Sí, este método también se usa ampliamente.
CoolMind
1
Esta no es una buena opción. FragmentContext y ApplicationContext tienen diferentes estilos. Fragment Context puede tener un tema oscuro, estilo personalizado, Locale, etc., que extraerá el color, los recursos de cadena de diferentes archivos. Si bien ApplicationContext puede no extraer el recurso correcto. Si no tiene Contexto, entonces no debería estar tratando de representar ese recurso.
Jemshit Iskenderov
2

Este error puede ocurrir si está creando una instancia de un fragmento que de alguna manera no se puede instanciar:

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
  }
}

En mi caso, me encontré con esto cuando intenté usar:

private String loading = getString(R.string.loading);
sagits
fuente
2

En uso de Fragment isAdded() Volverá verdadero si el fragmento está actualmente adjunto a Activity.

Si quieres consultar dentro de la Actividad

 Fragment fragment = new MyFragment();
   if(fragment.getActivity()!=null)
      { // your code here}
      else{
       //do something
       }

Espero que ayude a alguien

Prateek218
fuente
1

Adopté el siguiente enfoque para manejar este problema. Creó una nueva clase que actúa como un contenedor para métodos de actividad como este

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

}

Ahora, donde sea que necesite acceder a recursos de fragmentos o actividades, en lugar de llamar directamente al método, uso esta clase. En caso de que la actividad contextno lo nullsea, devuelve el valor del activo y en caso de que contextsea ​​nulo, pasa un valor predeterminado (que también especifica el llamador de la función).

Importante Esta no es una solución, es una forma efectiva de manejar este bloqueo con gracia. Debería agregar algunos registros en los casos en que obtenga una instancia de actividad como nula e intente solucionarlo, si es posible.

Ezio
fuente
0

Esto sucede cuando el fragmento no tiene contexto, por lo que el método getActivity () devuelve nulo. compruebe si usa el contexto antes de obtenerlo, o si la Actividad ya no existe. use el contexto en fragment.onCreate y después de la respuesta de la API, generalmente este caso

fan dexian
fuente
0

A veces, esta excepción es causada por un error en la implementación de la biblioteca de soporte. Recientemente tuve que bajar de 26.1.0 a 25.4.0 para deshacerme de él.

Bord81
fuente
No, no lo hago, pero tal vez debería crear uno.
Bord81
0

Este problema ocurre cada vez que llama a un contexto que no está disponible o es nulo cuando lo llama. Esto puede ser una situación cuando está llamando al contexto del hilo de actividad principal en un hilo de fondo o al contexto del hilo de fondo en el hilo de actividad principal.

Por ejemplo, actualicé mi cadena de preferencias compartidas como la siguiente.

editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();

Y llamó a finish () justo después. Ahora lo que hace es que como commit se ejecuta en el hilo principal y detiene cualquier otro commit asíncrono si llega hasta que finalice. Entonces su contexto está vivo hasta que se completa la escritura. Por lo tanto, el contexto anterior es en vivo, lo que provoca el error

Por lo tanto, asegúrese de volver a comprobar su código si hay algún código que tenga este problema de contexto.

Prashant Paliwal
fuente
¿Cómo lograste solucionar este problema? Lo estoy llamando dentro de un hilo asíncrono y estoy experimentando este problema ahora.
Simon
Solo asegúrese de que la operación de escritura haya finalizado, luego solo se elimina el contexto no antes de que se complete la operación de escritura.
Prashant Paliwal