getActivity () devuelve null en la función Fragment


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 (desde 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 se lo que es

Author: josemigallas, 2011-06-02

13 answers

commit programa la transacción, es decir, no sucede inmediatamente, pero se programa como trabajo en el hilo principal la próxima vez que el hilo principal esté listo.

Yo sugeriría agregar un

onAttach(Activity activity)

Método a su Fragment y poner un punto de interrupción en él y ver cuando 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 la Fragment está unida a su actividad y desde este punto getActivity() devolverá non-null (nb también hay una llamada onDetach()).

 148
Author: PJL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-23 05:31:50

Lo mejor para deshacerse de esto es mantener la referencia de actividad cuando se llama a onAttach 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;
}
 76
Author: Pawan Maheshwari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 11:22:17

Esto sucedió cuando llamas a getActivity() en otro hilo que terminó después de que se eliminara el fragmento. El caso típico es llamar getActivity() (ex. para un Toast) cuando una petición HTTP terminó (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, usualmente defino una clase base para todos mis Fragmentos con esto 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,

 60
Author: thucnguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-28 16:05:22

Desde el nivel 23 de la API de Android, onAttach(Activity activity) ha quedado obsoleto. Necesitas usar onAttach (Context context). http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

La actividad es un contexto por lo que si simplemente puede comprobar que el contexto es una actividad y enviarlo si es necesario.

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

    Activity a;

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

}
 16
Author: Sachin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-13 19:48:28

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

  1. Variables globales definidas para fragment:

    private final Object attachingActivityLock = new Object();

    private boolean syncVariable = false;

  2. Aplicada

@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 thread, porque si se ejecutara en el hilo principal, bloquearía el hilo con el paso 4. y onAttach () nunca sería llamada.

    Thread processImage = new Thread(new Runnable() {

        @Override
        public void run() {
            processImage();
        }
    });
    processImage.start();

4 . en mi función donde necesito para llamar a getActivity(), utilizo esto (antes de llamar a getActivity ())

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

Si tienes algunas actualizaciones de la interfaz de usuario, recuerda ejecutarlas en el subproceso de la interfaz de usuario. Necesito actualizar ImgeView así que lo hice:

image.post(new Runnable() {

    @Override
    public void run() {
        image.setImageBitmap(imageToShow);
    }
});
 9
Author: zajac.m2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-17 02:21:07

El orden en el 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 algún trabajo que involucrara algunas vistas, así que onAttach() no funcionó para mí; se bloqueó. Así que moví parte de mi código que estaba configurando algunos parámetros dentro de un método llamado justo después de commit() (1.), luego la otra parte del código que manejó la vista dentro onCreateView () (3.).

 7
Author: Bogdan Zurac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-01 14:06:40

Las otras respuestas que sugieren mantener una referencia a la actividad en onAttach solo sugieren un vendaje 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 suceda cuando la Actividad se ha ido debido a la rotación o la Actividad ha terminado, pero el Fragmento tiene algún tipo de oyente de devolución de llamada. Cuando se llama al oyente si necesitas hacer algo con la Actividad pero la Actividad se ha ido allí no hay mucho que puedas hacer. En su código solo debe comprobar getActivity() != null y si no está allí, entonces no haga nada. Si mantiene una referencia a la Actividad que se ha ido, está evitando que la Actividad sea recogida como basura. Cualquier cosa de la interfaz de usuario que pueda intentar hacer no será vista por el usuario. Puedo imaginar algunas situaciones en las que en el oyente de devolución de llamada es posible que desee tener un Contexto para algo no relacionado con la interfaz de usuario, 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 el oyente de devolución de llamada se ejecute, ya no será necesario y se puede recolectar basura junto con el Fragmento, todas sus Vistas y el contexto de la Actividad. Si setRetainInstance(true) hay una mayor probabilidad de una fuga de memoria porque el campo de Actividad también se conservará, pero después de la rotación que podría ser la actividad anterior no la actual.

 5
Author: miguel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-22 17:33:18

Haz lo siguiente. Creo que le será de ayuda.

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

}
 1
Author: Vinil Chandran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-21 13:04:39

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

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

 1
Author: Phạm Lam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 10:40:07

Estoy usando OkHttp y acabo de enfrentar este problema.


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

Esto sucedió cuando llamaste a getActivity() en otro subproceso que terminó después de que se eliminara el fragmento. El caso típico es llamar a getActivity () (ej. para un brindis) cuando una solicitud HTTP terminó (en onResponse, por ejemplo).

Algunas llamadas HTTP se estaban ejecutando incluso después de que la actividad se cerrado (porque puede tomar un tiempo para que una solicitud HTTP se complete). Entonces, a través de HttpCallback traté de actualizar algunos campos de fragmento 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

IMO la solución 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 echas un vistazo al ciclo de vida del fragmento (más información aquí ), observe que hay onAttach(Context context) y onDetach() métodos. Estos se llaman después de que el Fragmento pertenece a una actividad y justo antes de dejar de ser así respectivamente.

Eso significa que podemos evitar que ocurra esa devolución de llamada controlándola 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();
    }
}
 1
Author: zurfyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-03 16:20:21

Los que todavía tienen el problema con onAttach (Actividad actividad), Su acaba de cambiar 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 ti - por ejemplo, si quieres hacer getResources() puedes hacerlo directamente desde el contexto. Si todavía necesita hacer 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;
    }
}

Como sugiere user1868713.

 0
Author: Shai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-26 10:30:58

Puede usar onAttach o si no desea poner onAttach 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 reutilizarlo en todas partes en todo su proyecto, así:

App.getContext().getString(id)

Por Favor, hágamelo saber si esto no funciona para usted.

 0
Author: surga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-17 01:59:31

El mejor y sólido camino:

FragmentActivity activity = (FragmentActivity) getActivity();

activity.finish();
 -5
Author: Farhad Mammadli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-13 10:48:16