tutorial trabajar studio new implement how fragments fragmentos create con android android-fragments android-activity null android-context

android - trabajar - getActivity() devuelve nulo en la función de Fragmento



java android fragment (13)

Tengo un fragmento (F1) con un método público como este

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

y sí cuando lo llamo (de la Actividad), es nulo ...

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

Debe ser algo que estoy haciendo muy mal, pero no sé qué es eso


Estoy usando OkHttp y acabo de enfrentar este problema.

Para la primera parte, @thucnguyen estaba en el camino correcto .

Esto sucedió cuando llamas a getActivity () en otro hilo que finalizó después de que se eliminó el fragmento. El caso típico es llamar a getActivity () (por ejemplo, para un Toast) cuando termina una solicitud HTTP (en onResponse, por ejemplo).

Algunas llamadas HTTP se estaban ejecutando incluso después de que se cerrara la actividad (porque puede llevar un tiempo que se complete una solicitud HTTP). Luego, a través de HttpCallback intenté actualizar algunos campos de Fragmentos y obtuve una excepción null al intentar getActivity() .

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

La solución IMO es evitar que se produzcan devoluciones de llamada cuando el fragmento ya no está vivo (y eso no es solo con Okhttp).

La solución: Prevención.

Si onAttach(Context context) un vistazo al ciclo de vida del fragmento (más información here ), verás que hay onAttach(Context context) y onDetach() . Estos se llaman después de que el Fragmento pertenece a una actividad y justo antes de dejar de serlo, respectivamente.

Eso significa que podemos evitar que la devolución de llamada suceda controlando en el método 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(); } }


¿A dónde llamas esta función? Si lo llama en el constructor de Fragment , devolverá null .

Simplemente llame a getActivity() cuando se onCreateView() el método onCreateView() .


Aquellos que todavía tienen el problema con onAttach (actividad de actividad), simplemente cambió a Contexto -

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

En la mayoría de los casos, guardar el contexto será suficiente para usted; por ejemplo, si desea obtener getResources () puede hacerlo directamente desde el contexto. Si aún necesita convertir el contexto en su actividad, hágalo:

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

Según lo sugerido por el usuario1868713.


Desde el nivel 23 de la API de Android, onAttach (actividad de actividad) ha quedado obsoleto. Debe usar onAttach (Contexto contextual). http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

La actividad es un contexto, por lo que si simplemente puede verificar el contexto, se trata de una Actividad y emitirla si es necesario.

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


El orden en que se llaman las devoluciones de llamada después de commit ():

  1. Cualquier método que llame manualmente justo después de commit ()
  2. onAttach ()
  3. onCreateView ()
  4. onActivityCreated ()

Necesitaba hacer un trabajo que implicara algunas Vistas, por lo que onAttach () no funcionó para mí; se estrelló. Así que moví parte de mi código que estaba configurando algunos parámetros dentro de un método llamado inmediatamente después de commit () (1.), luego la otra parte del código que manejaba view inCreateView () (3.).


Esto sucedió cuando llamas a getActivity() en otro hilo que finalizó después de que se eliminó el fragmento. El caso típico es llamar a getActivity() (por ejemplo, para un Toast ) cuando termina una solicitud HTTP (en onResponse por ejemplo).

Para evitar esto, puede definir un nombre de campo mActivity y usarlo en lugar de getActivity() . Este campo se puede inicializar en el método onAttach () de Fragment de la siguiente manera:

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

En mis proyectos, generalmente defino una clase base para todos mis Fragmentos con esta característica:

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

Feliz codificación,


Haz lo siguiente. Creo que será útil para ti.

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 }


Las otras respuestas que sugieren que mantener una referencia a la actividad en ontach solo sugieren una curita al problema real. Cuando getActivity devuelve null, significa que el Fragmento no está adjunto a la Actividad. Lo más común es que esto ocurra cuando la Actividad se ha ido debido a la rotación o la Actividad que se ha terminado, pero el Fragmento tiene algún tipo de oyente de devolución de llamada. Cuando se llama al oyente si necesita hacer algo con la Actividad, pero la Actividad se ha ido, no hay mucho que pueda hacer. En su código solo debe verificar getActivity() != null y si no está allí, entonces no haga nada. Si mantiene una referencia a la Actividad que ha desaparecido, está impidiendo que la Actividad sea recolectada como basura. Cualquier UI que intente hacer no será visto por el usuario. Puedo imaginar algunas situaciones en las que en el oyente de devolución de llamada podría querer tener un contexto para algo que no esté relacionado con la UI, en esos casos, probablemente tenga más sentido obtener el contexto de la aplicación. Tenga en cuenta que la única razón por la que el truco onAttach no es una gran pérdida de memoria es porque, normalmente, después de que se ejecuta el escucha de devolución de llamada ya no será necesario y puede ser recolectado junto con el Fragmento, todas sus Vistas y el contexto de la Actividad. Si setRetainInstance(true) existe una mayor posibilidad de una pérdida de memoria porque el campo Actividad también se mantendrá, pero después de la rotación podría ser la Actividad anterior, no la actual.


Lo mejor para deshacerse de esto es mantener la referencia de actividad cuando se llama a ontach y usar la referencia de actividad donde sea necesario, por ejemplo

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


Mejor y sólida manera:

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


PJL tiene razón. He usado su sugerencia y esto es lo que he hecho:

  1. variables globales definidas para fragmento:

    private final Object attachingActivityLock = new Object();

    private boolean syncVariable = false;

  2. implementado

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

3. Envolví mi función, donde necesito llamar a getActivity (), en el hilo, porque si se ejecutara en el hilo principal, bloquearía el hilo con el paso 4. y nunca se llamaría a Ontach ().

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

4. en mi función donde necesito llamar a getActivity (), uso esto (antes de la llamada getActivity ())

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

Si tiene algunas actualizaciones de UI, recuerde ejecutarlas en el hilo de UI. Necesito actualizar ImgeView así que lo hice:

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


Puede usar onAttach o si no desea poner en Attch en todas partes, puede poner un método que devuelva ApplicationContext en la clase principal de la aplicación:

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

Después de eso, puede volver a usarlo en todas partes en todo su proyecto, así:

App.getContext().getString(id)

Por favor, avíseme si esto no funciona para usted.


commit programa la transacción, es decir, no ocurre de inmediato, sino que está programada como trabajo en el hilo principal la próxima vez que el hilo principal esté listo.

Sugeriría agregar un

onAttach(Activity activity)

método para su Fragment y ponerle un punto de interrupción y ver cuándo se llama en relación con su llamada a asd() . Verá que se llama después del método donde realiza la llamada a asd() exits. La llamada onAttach es donde el Fragment está conectado a su actividad y desde este punto getActivity() devolverá no nulo (nb también hay una llamada onDetach() ).