Android Fragment onAttach () obsoleto


326

Ho aggiornato la mia app per utilizzare l'ultima libreria di supporto (versione 23.0.0), ho scoperto che hanno deprecato la funzione onAttach () della classe Fragment.

Invece di:

onAttach (Activity activity)

Nevica:

onAttach (Context context)

Poiché la mia app utilizza l'attività passata prima dell'ammortamento, una possibile soluzione che penso sia:

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

Sarebbe il modo corretto di farlo?

AGGIORNARE:

Se eseguo un dispositivo con API inferiore a 23, il nuovo onAttach () non viene nemmeno chiamato. Spero che non sia quello che intendevano fare!

AGGIORNAMENTO 2:

Il problema è stato risolto con gli ultimi aggiornamenti dell'SDK.

Ho provato sul mio dispositivo API 22 e onAttach (Context) viene chiamato.

Fai clic qui per seguire la segnalazione di bug che ho aperto un paio di settimane fa e le risposte dei ragazzi di Google.


Se stai utilizzando metodi di attività specifici dalla tua istanza passata, hai provato a trasmettere il contesto a quello della tua attività? Ricorda L'attività è una sottoclasse del contesto. Forse un casting avrebbe funzionato.
MarkSkayff,

per qualche ragione, onAttach () non viene nemmeno chiamato! qualche idea? hai provato ad aggiornare all'ultima libreria di supporto.?
TareK Khoury,

2
Perché l'API è stata spostata Context? Non hai bisogno di un Activityper allegare e visualizzare comunque un frammento? In quale altro modo utilizzerai il Contextparametro?
Kenny Worden,

1
L'ho pubblicato come bug, vedi link code.google.com/p/android/issues/detail?id=183358
TareK Khoury

6
Per onAttach(Context context)poter chiamare il nuovo , è necessario utilizzare un dispositivo che abbia almeno API 23 OPPURE utilizzare android.support.v4.app.Fragment. Vedi qui
nevzo,

Risposte:


337

L'attività è un contesto, quindi se puoi semplicemente controllare il contesto è un'attività e lanciarla se necessario.

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

    Activity a;

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

}

Aggiornamento: alcuni sostengono che il nuovo Contextoverride non viene mai chiamato. Ho fatto alcuni test e non riesco a trovare uno scenario in cui questo è vero e secondo il codice sorgente, non dovrebbe mai essere vero. In tutti i casi che ho provato, sia pre che post SDK23, sono state chiamate sia Activityla Contextversione che la versione di onAttach. Se riesci a trovare uno scenario in cui non è così, ti suggerirei di creare un progetto di esempio che illustri il problema e lo riferisca al team di Android .

Aggiornamento 2: utilizzo sempre e solo i frammenti della libreria di supporto Android poiché i bug vengono corretti più velocemente lì. Sembra che il problema precedente in cui le sostituzioni non vengano chiamate correttamente venga alla luce solo se si utilizzano i frammenti del framework.


5
Non è davvero una soluzione poiché onAttach con contesto non è chiamato allo stesso modo di onAttach con attività. Se hai un codice di inizializzazione in onAttach con un'attività come parametro questa modifica non funzionerà.
Amico,

2
No, non funziona allo stesso modo, almeno nel mio caso. Non utilizzo attività né contesto in onAttach, eseguo l'inizializzazione. Ho provato a sostituire onAttach con attività con quello con contesto e non viene chiamato allo stesso modo. Quindi non sono così facilmente intercambiabili.
Amico,

7
Gli stessi problemi che Buddy ha ... onAttach(Context)non sembra nemmeno essere chiamato.
Stéphane,

2
Ho esaminato il mio codice e posso verificare che non è possibile onAttach(context)chiamarlo.
Chad Bingham,

2
Nel mio caso, onAttach () non verrà chiamato se si riavvia l'attività precedentemente cancellata dal sistema. Ma non è sempre così. Ho inserito un'inizializzazione di un WeakReference nel contesto onAttach (contesto di contesto), refActivity = new WeakReference <> ((AppCompatActivity)). E lancia NullPointerException in onCreateView () di tanto in tanto.
Kimi Chiu,

45

Questo è un altro grande cambiamento da parte di Google ... La modifica suggerita: sostituisci onAttach(Activity activity)con le onAttach(Context context)mie app bloccate su API più vecchie poiché onAttach(Context context)non verranno chiamate su frammenti nativi.

Sto usando i frammenti nativi (android.app.Fragment), quindi ho dovuto fare quanto segue per farlo funzionare di nuovo sulle API più vecchie (<23).

Ecco cosa ho fatto:

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

Mr.Yoann Hercouet, mi può spiegare come farlo sopra API 23, mi aiuti gentilmente, grazie in anticipo, E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, su android. support.v4.app.FragmentManagerImpl.moveToState, su android.support.v4.app.FragmentManagerImpl.execSingleAction. Qui ho pubblicato le righe necessarie per conoscere il mio bug.
MohanRaj S

@MohanRajS È lo stesso su API 24 (quello che ho usato), secondo il tuo codice, il tuo problema non sembra avere nulla a che fare con questo.
Yoann Hercouet,

@YoannHercouet, Grazie per la tua risposta, fammi controllare e aggiornare.
MohanRaj S

1
Non sei contento di Google su questo a causa della difficoltà di indirizzare le API più vecchie. Bene, considera la benedizione che PUOI prendere di mira le API più vecchie, mentre Apple, ad esempio, ti limiterebbe tremendamente e ti costringerebbe a supportare solo le più recenti.
Stan

39

Se si utilizzano i frammenti del framework e la versione dell'SDK del dispositivo è inferiore a 23, OnAttach(Context context)non verrebbero chiamati.

Uso invece i frammenti di supporto, quindi la deprecazione è fissa e onAttach(Context context)viene sempre chiamata.


11

Attualmente dal onAttachcodice del frammento, non è chiaro se Contextè l'attività corrente: il codice sorgente

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

Se darai un'occhiata getActivityvedrai la stessa chiamata

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

Quindi, se si vuole essere sicuri che si stanno ottenendo l'Activity quindi utilizzare getActivity()(in onAttachnel vostro Fragment), ma non dimenticate di verificare la presenza di nullperché se mHostè nullla vostra attività sarànull


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

    Activity activity = context instanceof Activity ? (Activity) context : null;
}

5

Anche se sembra che nella maggior parte dei casi sia sufficiente onAttach(Context), ci sono alcuni telefoni (ad esempio: Xiaomi Redme Note 2) in cui non viene chiamato, quindi provoca NullPointerExceptions. Quindi, per essere al sicuro, suggerisco di lasciare anche il metodo deprecato:

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

3

Scarica la più recente libreria di supporto con il gestore sdk e includi

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

in gradle.app e imposta la versione di compilazione su api 23


1

La risposta di seguito è correlata a questo avviso di deprecazione che si verifica nell'esercitazione sui frammenti sul sito Web degli sviluppatori Android e potrebbe non essere correlata ai post precedenti.

Ho usato questo codice nella lezione del tutorial e ha funzionato.

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

    Activity activity = getActivity();

Ero preoccupato che l'attività potesse essere nulla come indicato nella documentazione.

getActivity

FragmentActivity getActivity () Restituisce FragmentActivity a cui questo frammento è attualmente associato. Può restituire null se il frammento è invece associato a un contesto.

Ma onCreate su main_activity mostra chiaramente che il frammento è stato caricato e quindi dopo questo metodo, chiamando get attività dal frammento restituirà la classe main_activity.

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

Spero di essere corretto con questo. Sono un principiante assoluto.


1

probabilmente stai usando android.support.v4.app.Fragment. Per questo invece del onAttachmetodo, basta usare getActivity()per ottenere FragmentActivitya cui è associato il frammento. Altrimenti potresti usare il onAttach(Context context)metodo.


0

Questo ha funzionato per me quando ho definito l'interfaccia "TopSectionListener", il suo oggetto taskcommander:

  //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());}

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.