Perché voglio evitare costruttori non predefiniti nei frammenti?


173

Sto creando un'app con Fragmentse in una di esse ho creato un costruttore non predefinito e ho ricevuto questo avviso:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

Qualcuno può dirmi perché questa non è una buona idea?

Puoi anche suggerire come farei questo:

public static class MenuFragment extends ListFragment {
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category){
        this.category = category;
    }....

Senza usare il costruttore non predefinito?



3
No, quelli non aiutano. Non hanno risposto alla mia domanda. Ma grazie comunque :)
BlackHatSamurai

31
@BlaineOmega In realtà questo in particolare: stackoverflow.com/a/11602478/321697 risponde sicuramente alla tua domanda. In caso di modifica dell'orientamento o altro evento che causa la ricostruzione del frammento, Android utilizza il costruttore predefinito e il pacchetto passato come argomento. Se stai usando un costruttore personalizzato, non appena il frammento viene ricreato a causa di uno di questi eventi, tutto ciò che hai fatto nel costruttore personalizzato viene perso.
Kevin Coppock,

1
Grazie, ma questo risponde al perché, ma non al come.
BlackHatSamurai,

Questo è coperto dal primo e dal secondo link nel mio commento originale.
Commons War

Risposte:


110

Crea un oggetto bundle e inserisci i tuoi dati (in questo esempio il tuo Categoryoggetto). Fai attenzione, non puoi passare questo oggetto direttamente nel bundle, a meno che non sia serializzabile. Penso che sia meglio costruire il tuo oggetto nel frammento e mettere in bundle solo un ID o qualcos'altro. Questo è il codice per creare e allegare un pacchetto:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

Successivamente, nel tuo frammento accedi ai dati:

Type value = getArguments().getType("key");

È tutto.


3
come passare un oggetto? Voglio passare un oggetto di contesto o qualsiasi altro oggetto.
Adil Malik,

12
I pacchetti possono contenere sia oggetti serializzati Java che Parcelableoggetti. Inoltre, non dovresti passare a Context, perché è possibile accedere a tali informazioni tramite il getActivity()metodo del frammento .
krakatoa,

In frammento dove farlo Type value = getArguments().getType("key");?
Muhammad Babar

4
@Muhammad Babar: se fossi in te, lo aggiungerei al newInstance()metodo. Ad esempio: public static FragmentName newInstance(your variables){}. Come raccomandato dalla documentazione Android, non creare un costruttore con parametri, poiché quello predefinito (senza parametri) verrà chiamato automaticamente dopo il riavvio del frammento.
nistv4n,

@MuhammadBabar onCreateView is OK
chanjianyi

272

Sembra che nessuna delle risposte in realtà risponda "perché usare il bundle per passare parametri anziché costruttori non predefiniti"

Il motivo per cui dovresti passare i parametri attraverso il bundle è perché quando il sistema ripristina un fragment(ad es. Al cambio di configurazione), ripristinerà automaticamente il tuo bundle.

I callback gradiscono onCreateo onCreateViewdovrebbero leggere i parametri dal bundle- in questo modo si è certi di ripristinare lo stato del fragmentcorrettamente nello stesso stato con cui è fragmentstato inizializzato (si noti che questo stato può essere diverso da onSaveInstanceState bundlequello passato al onCreate/onCreateView)

La raccomandazione di usare il newInstance()metodo statico è solo una raccomandazione. È possibile utilizzare un costruttore non predefinito ma assicurarsi di popolare i parametri di inizializzazione bundleall'interno del corpo di quel costruttore. E leggi quei parametri nei metodi onCreate()o onCreateView().


2
Ben spiegato. Grazie. Se fossi stato io a porre la domanda, ti avrei dato un segno di spunta
Karue Benson Karue,

5
Non puoi più usare il costruttore non predefinito (per qualsiasi motivo) .... dà un errore del compilatore (usato per essere un avvertimento).
MPavlak,

51

Il vostro Fragmentnon dovrebbe avere costruttori a causa del modo in cui il FragmentManagercrea un'istanza di esso. È necessario disporre di un newInstance()metodo statico definito con i parametri necessari, quindi raggrupparli e impostarli come argomenti del frammento, a cui è possibile accedere in seguito con il Bundleparametro.

Per esempio:

public static MyFragment newInstance(int title, String message) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;
}

E leggi questi argomenti su onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
}

In questo modo, se scollegato e ricollegato, lo stato dell'oggetto può essere memorizzato attraverso gli argomenti, in modo molto simile bundlesa Intents.


9

Se si utilizza il parametro per alcune classi. prova questo

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}

5
Questo è in realtà un suggerimento negativo. Una volta che il frammento verrà ricreato da un FragmentManager, perderai mSomeInstance.
Yaroslav Mytkalyk,

D'accordo, SomeClass dovrebbe essere parcelable e archiviato in un bundle usando setArguments ()
Jake_27

1

Penso che non vi sia alcuna differenza tra il costruttore statico e due costruttori (uno vuoto e parametrizzato che memorizza gli argomenti in un bundle di argomenti di un frammento), molto probabilmente, questa regola empirica viene creata per ridurre la probabilità di dimenticare di implementare il costruttore no-arg in Java , che non viene generato implicitamente in presenza di sovraccarico.

Nei miei progetti utilizzo Kotlin e implemento frammenti con un costruttore no-arg primario e un costruttore secondario per argomenti che li memorizza semplicemente in un bundle e lo imposta come argomenti di frammenti, tutto funziona bene.


0

Se il frammento utilizza costruttori non predefiniti dopo aver modificato la configurazione, il frammento perderà tutti i dati.

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.