Fragment Android onAttach () déconseillé

326

J'ai mis à jour mon application pour utiliser la dernière bibliothèque de support (version 23.0.0), j'ai découvert qu'ils ont déconseillé la fonction onAttach () de la classe Fragment.

Au lieu de:

onAttach (Activity activity)

La neige:

onAttach (Context context)

Comme mon application utilise l'activité passée avant la dépréciation, je pense qu'une solution possible est:

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

Serait-ce la bonne façon de procéder?

METTRE À JOUR:

Si j'exécute un appareil avec une API inférieure à 23, le nouveau onAttach () n'est même pas appelé. J'espère que ce n'est pas ce qu'ils avaient l'intention de faire!

MISE À JOUR 2:

Le problème a été résolu avec les dernières mises à jour du SDK.

J'ai testé sur mon appareil API 22 et onAttach (Context) est appelé.

Cliquez ici pour suivre le rapport de bogue que j'ai ouvert il y a quelques semaines et les réponses des gars de Google.

TareK Khoury
la source
Si vous utilisez des méthodes d'activité spécifiques de votre instance passée, avez-vous essayé de caster le contexte dans votre activité? N'oubliez pas que l'activité est une sous-classe de contexte. Peut-être qu'un casting fonctionnerait.
MarkSkayff
pour une raison quelconque, onAttach () n'est même pas appelé! des idées? avez-vous essayé de mettre à jour la dernière bibliothèque de support?
TareK Khoury
2
Pourquoi l'API a-t-elle migré Context? N'avez-vous pas besoin d'un Activitypour attacher et afficher un fragment de toute façon? Sinon, comment utiliserez-vous le Contextparamètre?
Kenny Worden
1
Je l'ai signalé en tant que bogue, voir le lien code.google.com/p/android/issues/detail?id=183358
TareK Khoury
6
Pour que le nouveau onAttach(Context context)soit appelé, vous devez soit utiliser un appareil doté d'au moins API 23 OU utiliser android.support.v4.app.Fragment. Voir ici
nevzo

Réponses:

337

L'activité est un contexte, donc si vous pouvez simplement vérifier que le contexte est une activité et la diffuser si nécessaire.

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

    Activity a;

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

}

Mise à jour: certains prétendent que le nouveau Contextremplacement n'est jamais appelé. J'ai fait quelques tests et je ne trouve pas de scénario où cela est vrai et selon le code source, cela ne devrait jamais être vrai. Dans tous les cas, j'ai testé, à la fois avant et après SDK23, Activityles Contextversions et les versions de onAttachont été appelées. Si vous pouvez trouver un scénario où ce n'est pas le cas, je vous suggère de créer un exemple de projet illustrant le problème et de le signaler à l'équipe Android .

Mise à jour 2: je n'utilise que les fragments de la bibliothèque de support Android car les bogues y sont corrigés plus rapidement. Il semble que le problème ci-dessus où les remplacements ne sont pas appelés correctement ne se révèle que si vous utilisez les fragments de framework.

Kuffs
la source
5
Pas vraiment une solution car onAttach avec contexte n'est pas appelé de la même manière que onAttach avec activité. Si vous avez du code d'initialisation dans onAttach avec une activité comme paramètre, cette modification ne fonctionnera pas.
Buddy
2
Non, cela ne fonctionne pas de la même façon, du moins dans mon cas. Je n'utilise ni activité ni contexte dans onAttach, je fais l'initialisation. J'ai essayé de remplacer onAttach avec activité par celui avec contexte et il n'est pas appelé de la même manière. Ils ne sont donc pas aussi facilement interchangeables.
Buddy
7
Les mêmes problèmes que Buddy a ... onAttach(Context)ne semblent même pas s'appeler.
Stéphane
2
J'ai parcouru mon code et je peux vérifier qu'il est possible onAttach(context)de ne pas être appelé.
Chad Bingham
2
Dans mon cas, onAttach () ne sera pas appelé si nous redémarrons l'activité qui est effacée par le système auparavant. Mais ce n'est pas toujours comme ça. J'ai mis une initialisation d'une WeakReference dans le onAttach (Context context), refActivity = new WeakReference <> ((AppCompatActivity) context). Et il lève occasionnellement NullPointerException dans onCreateView ().
Kimi Chiu
45

Ceci est un autre grand changement de Google ... La modification suggérée: remplacer onAttach(Activity activity)par onAttach(Context context)planter mes applications sur les anciennes API car onAttach(Context context)ne sera pas appelé sur les fragments natifs.

J'utilise les fragments natifs (android.app.Fragment), j'ai donc dû faire ce qui suit pour le faire fonctionner à nouveau sur les anciennes API (<23).

Voici ce que j'ai fait:

@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
la source
Mr.Yoann Hercouet, pouvez-vous expliquer comment le faire au-dessus de l'API 23, veuillez m'aider, merci d'avance, E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, sur android. support.v4.app.FragmentManagerImpl.moveToState, sur android.support.v4.app.FragmentManagerImpl.execSingleAction. Ici, j'ai posté les lignes nécessaires qui vous permettront de connaître mon bug.
MohanRaj S
@MohanRajS C'est la même chose sur l'API 24 (celle que j'ai utilisée), selon votre morceau de code, votre problème ne semble pas avoir à faire quoi que ce soit avec cela.
Yoann Hercouet
@YoannHercouet, merci pour votre réponse, laissez-moi vérifier et mettre à jour.
MohanRaj S
1
Vous n'êtes pas satisfait de Google à ce sujet en raison de la difficulté à cibler les anciennes API. Eh bien, considérez la bénédiction que vous pouvez cibler les anciennes API, alors qu'Apple, par exemple, vous paralyserait énormément et vous forcerait à ne prendre en charge que les plus récentes.
Stan
39

Si vous utilisez les fragments d'infrastructure et que la version SDK de l'appareil est inférieure à 23, OnAttach(Context context)elle ne sera pas appelée.

J'utilise des fragments de support à la place, donc la dépréciation est corrigée et onAttach(Context context)toujours appelée.

kikermo
la source
11

Actuellement à partir du onAttachcode de fragment, il n'est pas clair si Contextc'est l'activité actuelle: Code source

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

Si vous regardez, getActivityvous verrez le même appel

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

Donc , si vous voulez être sûr que vous obtenez l'activité puis utilisez getActivity()(dans onAttachvotre Fragment) mais ne pas oublier de vérifier nullparce que si mHostest nullvotre activité seranull

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

    Activity activity = context instanceof Activity ? (Activity) context : null;
}
travaillé
la source
5

Bien qu'il semble que dans la plupart des cas, cela soit suffisant onAttach(Context), il existe certains téléphones (par exemple: Xiaomi Redme Note 2) où il n'est pas appelé, ce qui provoque donc des exceptions NullPointerExceptions. Donc, pour être prudent, je suggère de laisser la méthode obsolète également:

// 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
la source
3

Téléchargez la dernière bibliothèque de support avec le gestionnaire sdk et incluez

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

dans gradle.app et définissez la version de compilation sur api 23

Essah
la source
1

La réponse ci-dessous est liée à cet avertissement de dépréciation apparaissant dans le didacticiel Fragments sur le site Web des développeurs Android et peut ne pas être lié aux messages ci-dessus.

J'ai utilisé ce code dans la leçon du didacticiel et cela a fonctionné.

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

    Activity activity = getActivity();

J'avais peur que cette activité soit nulle comme l'indique la documentation.

getActivity

FragmentActivity getActivity () Retourne la FragmentActivity à laquelle ce fragment est actuellement associé. Peut retourner null si le fragment est associé à un contexte à la place.

Mais onCreate sur la main_activity montre clairement que le fragment a été chargé et donc après cette méthode, l'appel à l'activité get du fragment retournera la classe main_activity.

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

J'espère avoir raison. Je suis un débutant absolu.

Roy Selim
la source
1

vous utilisez probablement android.support.v4.app.Fragment. Pour cela au lieu de onAttachméthode, utilisez simplement getActivity()pour obtenir le FragmentActivityfichier auquel le fragment est associé. Sinon, vous pouvez utiliser la onAttach(Context context)méthode.

LeoCoder
la source
0

Cela a fonctionné pour moi lorsque j'ai une interface définie par l'utilisateur 'TopSectionListener', sa commande d'activité d'objet:

  //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
la source