Android Fragment onAttach () en desuso

326

He actualizado mi aplicación para usar la última biblioteca de soporte (versión 23.0.0), descubrí que desaprobaron la función onAttach () de la clase Fragment.

En vez de:

onAttach (Activity activity)

Nieva:

onAttach (Context context)

Como mi aplicación usa la actividad pasada antes de la depreciación, creo que una posible solución es:

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

¿Sería esa la forma correcta de hacerlo?

ACTUALIZAR:

Si ejecuto un dispositivo con API inferior a 23, ni siquiera se llama al nuevo onAttach (). ¡Espero que esto no sea lo que pretendían hacer!

ACTUALIZACIÓN 2:

El problema se ha resuelto con las últimas actualizaciones del SDK.

He probado en mi dispositivo API 22 y se está llamando a onAttach (Context).

Haga clic aquí para seguir el informe de error que abrí hace un par de semanas y las respuestas de los chicos de Google.

TareK Khoury
fuente
Si está utilizando métodos de actividad específicos de su instancia pasada, ¿ha intentado transmitir el contexto a su actividad? Recordar actividad es una subclase de contexto. Tal vez un casting funcionaría.
MarkSkayff
¡Por alguna razón, ni siquiera se llama a onAttach ()! ¿algunas ideas? ¿Intentaste actualizar a la última lib de soporte?
TareK Khoury
2
¿Por qué se ha movido la API Context? ¿No necesita un Activitypara adjuntar y mostrar un fragmento de todos modos? ¿De qué otra forma usará el Contextparámetro?
Kenny Worden
1
Lo publiqué
TareK Khoury
66
Para onAttach(Context context)que se llame a lo nuevo , debe usar un dispositivo que tenga al menos API 23 O usar android.support.v4.app.Fragment. Ver aquí
nevzo

Respuestas:

337

La actividad es un contexto, por lo que si simplemente puede verificar el contexto, es 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;
    }

}

Actualización: Algunos afirman que Contextnunca se llama a la nueva anulación. He realizado algunas pruebas y no puedo encontrar un escenario en el que esto sea cierto y, según el código fuente, nunca debería ser cierto. En todos los casos Probé, tanto pre y SDK23 post, tanto el Activityy las Contextversiones de onAttachfueron llamados. Si puede encontrar un escenario en el que este no sea el caso, le sugiero que cree un proyecto de muestra que ilustre el problema y lo informe al equipo de Android .

Actualización 2: solo uso los fragmentos de la Biblioteca de soporte de Android ya que los errores se corrigen más rápido allí. Parece que el problema anterior en el que las anulaciones no se llaman correctamente solo sale a la luz si usa los fragmentos de marco.

Kuffs
fuente
55
No es realmente una solución ya que onAttach con contexto no se llama de la misma manera que onAttach con actividad. Si tiene algún código de inicialización en onAttach con una actividad como parámetro, este cambio no funcionará.
Amigo
2
No, no funciona igual, al menos en mi caso. No uso actividad ni contexto en onAttach, hago inicialización. Intenté reemplazar onAttach con actividad por el contexto y no se llama de la misma manera. Por lo tanto, no son tan fácilmente intercambiables.
Amigo
77
Los mismos problemas que tiene Buddy ... onAttach(Context)ni siquiera parecen llamarse.
Stéphane
2
He revisado mi código y puedo verificar que es posible onAttach(context)que no se me llame.
Chad Bingham
2
En mi caso, no se llamará a onAttach () si reiniciamos la actividad que el sistema borró antes. Pero no siempre es así. Puse una inicialización de una WeakReference en onAttach (Context context), refActivity = new WeakReference <> ((AppCompatActivity) context). Y arroja NullPointerException en onCreateView () ocasionalmente.
Kimi Chiu
45

Este es otro gran cambio de Google ... La modificación sugerida: reemplazar onAttach(Activity activity)con onAttach(Context context)mis aplicaciones bloqueadas en API anteriores ya onAttach(Context context)que no se invocará en fragmentos nativos.

Estoy usando los fragmentos nativos (android.app.Fragment), así que tuve que hacer lo siguiente para que funcione nuevamente en las API más antiguas (<23).

Aquí esta lo que hice:

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

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}
Yoann Hercouet
fuente
Sr.Yoann Hercouet, ¿Puede explicar cómo hacerlo por encima de la API 23, amablemente ayúdeme, gracias de antemano, E / AndroidRuntime: EXCEPCIÓN FATAL: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, en Android. support.v4.app.FragmentManagerImpl.moveToState, en android.support.v4.app.FragmentManagerImpl.execSingleAction. Aquí publiqué las líneas necesarias que conocerán mi error.
MohanRaj S
@MohanRajS Es lo mismo en la API 24 (la que usé), según su código, su problema no parece tener que ver con esto.
Yoann Hercouet
@YoannHercouet, Gracias por tu respuesta, déjame verificar y actualizar.
MohanRaj S
1
No está satisfecho con Google sobre esto debido a la dificultad para apuntar a las API más antiguas. Bueno, considere la bendición de que PUEDE apuntar a las API más antiguas, mientras que Apple, por ejemplo, simplemente lo paralizaría enormemente y lo obligaría a apoyar solo a los más nuevos.
Stan
39

Si utiliza los fragmentos de marco y la versión SDK del dispositivo es inferior a 23, OnAttach(Context context)no se llamaría.

En su lugar, uso fragmentos de soporte, por lo que la desaprobación se corrige y onAttach(Context context)siempre se llama.

kikermo
fuente
11

Actualmente del onAttachcódigo Fragment, no está claro si esta Contextes la actividad actual: Código fuente

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

Si echas un vistazo getActivity, verás la misma llamada

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

Así que si usted quiere estar seguro de que está recibiendo la Actividad luego usar getActivity()(en onAttachen tu Fragment), pero no se olvide de comprobar nullporque si mHostes nullserá su actividadnull

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

    Activity activity = context instanceof Activity ? (Activity) context : null;
}
trabajó
fuente
5

Aunque parece que en la mayoría de los casos es suficiente onAttach(Context), hay algunos teléfonos (es decir: Xiaomi Redme Note 2) donde no se llama, por lo que causa NullPointerExceptions. Entonces, para estar seguro, sugiero dejar también el método obsoleto:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

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

private void _onAttach(Context context) {
    // do your real stuff here
}
Gavriel
fuente
3

Descargue la biblioteca de soporte más reciente con el administrador de SDK e incluya

compile 'com.android.support:appcompat-v7:23.1.1'

en gradle.app y configura la versión de compilación a la API 23

Essah
fuente
1

La respuesta a continuación está relacionada con esta advertencia de desaprobación que se produce en el tutorial Fragmentos en el sitio web para desarrolladores de Android y puede no estar relacionada con las publicaciones anteriores.

Usé este código en la lección del tutorial y funcionó.

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

    Activity activity = getActivity();

Me preocupaba que la actividad pudiera ser nula como lo indica la documentación.

getActivity

FragmentActivity getActivity () Devuelve la FragmentActivity con la que este fragmento está asociado actualmente. Puede devolver nulo si el fragmento está asociado con un contexto en su lugar.

Pero onCreate en main_activity muestra claramente que el fragmento se cargó y, por lo tanto, después de este método, llamar a get activity desde el fragmento devolverá la clase main_activity.

getSupportFragmentManager (). beginTransaction () .add (R.id.fragment_container, firstFragment) .commit ();

Espero estar en lo correcto con esto. Soy un novato absoluto.

Roy Selim
fuente
1

Probablemente estés usando android.support.v4.app.Fragment. Para esto, en lugar del onAttachmétodo, solo use getActivity()para obtener el FragmentActivitycon el que está asociado el fragmento. De lo contrario, podría usar el onAttach(Context context)método.

LeoCoder
fuente
0

Esto funcionó para mí cuando definí la interfaz 'TopSectionListener', su comandante de actividad de objetos:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

}
Agarwal Muskan
fuente