Warum möchte ich nicht standardmäßige Konstruktoren in Fragmenten vermeiden?


173

Ich erstelle eine App mit Fragmentsund in einer davon habe ich einen nicht standardmäßigen Konstruktor erstellt und die folgende Warnung erhalten:

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

Kann mir jemand sagen, warum das keine gute Idee ist?

Können Sie auch vorschlagen, wie ich dies erreichen würde:

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

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

Ohne den nicht standardmäßigen Konstruktor zu verwenden?



3
Nein, die helfen nicht. Sie haben meine Frage nicht beantwortet. Aber trotzdem danke :)
BlackHatSamurai

31
@BlaineOmega Eigentlich ist dies besonders: stackoverflow.com/a/11602478/321697 beantwortet definitiv Ihre Frage. Bei einer Orientierungsänderung oder einem anderen Ereignis, bei dem das Fragment neu erstellt wird, verwendet Android den Standardkonstruktor sowie das als Argument übergebene Bundle. Wenn Sie einen benutzerdefinierten Konstruktor verwenden, geht alles, was Sie im benutzerdefinierten Konstruktor getan haben, verloren, sobald das Fragment aufgrund eines dieser Ereignisse neu erstellt wird.
Kevin Coppock

1
Danke, aber das beantwortet das Warum, aber nicht das Wie.
BlackHatSamurai

Dies wird durch den ersten und zweiten Link in meinem ursprünglichen Kommentar abgedeckt.
CommonsWare

Antworten:


110

Erstellen Sie ein Bündelobjekt und fügen Sie Ihre Daten ein (in diesem Beispiel Ihr CategoryObjekt). Seien Sie vorsichtig, Sie können dieses Objekt nicht direkt an das Bundle übergeben, es sei denn, es ist serialisierbar. Ich denke, es ist besser, Ihr Objekt in das Fragment zu bauen und nur eine ID oder etwas anderes in ein Bündel zu packen. Dies ist der Code zum Erstellen und Anhängen eines Bundles:

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

Danach in Ihrem Fragment Zugriffsdaten:

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

Das ist alles.


3
Wie übergebe ich ein Objekt? Ich möchte ein Kontextobjekt oder ein anderes Objekt übergeben.
Adil Malik

12
Bundles können sowohl serialisierte Java-Objekte als auch ParcelableObjekte enthalten. Sie sollten auch kein a übergeben Context, da auf diese Informationen über die getActivity()Methode des Fragments zugegriffen werden kann .
Krakatoa

In Fragment, wo dies zu tun Type value = getArguments().getType("key");?
Muhammad Babar

4
@ Muhammad Babar: Wenn ich du wäre, würde ich es der newInstance()Methode hinzufügen . Zum Beispiel : public static FragmentName newInstance(your variables){}. Erstellen Sie, wie in der Android-Dokumentation empfohlen, keinen Konstruktor mit Parametern, da der Standardkonstruktor (ohne Parameter) nach dem Neustart Ihres Fragments automatisch aufgerufen wird.
nistv4n

@ MuhammadBabar onCreateView ist in Ordnung
Chanjianyi

272

Es scheint, als würde keine der Antworten tatsächlich antworten: "Warum Bundle zum Übergeben von Parametern anstelle von nicht standardmäßigen Konstruktoren verwenden?"

Der Grund, warum Sie Parameter durch das Bundle übergeben sollten, liegt darin, dass das System beim Wiederherstellen von a fragment(z. B. bei Konfigurationsänderung) Ihre automatisch wiederherstellt bundle.

Die Rückrufe mögen onCreateoder onCreateViewsollten die Parameter aus dem lesen bundle- auf diese Weise wird garantiert, dass der Zustand des fragmentkorrekt in den Zustand zurückgesetzt wird, mit dem er fragmentinitialisiert wurde (beachten Sie, dass dieser Zustand von dem Zustand abweichen kann onSaveInstanceState bundle, der an übergeben wird onCreate/onCreateView).

Die Empfehlung, die statische newInstance()Methode zu verwenden, ist nur eine Empfehlung. Sie können einen nicht standardmäßigen Konstruktor verwenden, stellen Sie jedoch sicher, dass Sie die Initialisierungsparameter im bundleInneren des Konstruktors ausfüllen. Und lesen Sie diese Parameter in den Methoden onCreate()oder onCreateView().


2
Gut erklärt. Vielen Dank. Wenn ich derjenige gewesen wäre, der die Frage gestellt hätte, hätte ich Ihnen ein Häkchen gegeben
Karue Benson Karue

5
Sie können keinen nicht standardmäßigen Konstruktor mehr verwenden (aus welchem ​​Grund auch immer). Es wird ein Compilerfehler ausgegeben (früher eine Warnung).
MPavlak

51

Sie Fragmentsollten keine Konstruktoren haben, da diese FragmentManagerinstanziiert werden. Sie sollten eine newInstance()statische Methode mit den benötigten Parametern definieren, diese dann bündeln und als Argumente des Fragments festlegen, auf die Sie später mit dem BundleParameter zugreifen können .

Beispielsweise:

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

Und lesen Sie diese Argumente unter onCreate:

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

    //...
}

Auf diese Weise kann der Objektstatus, wenn er getrennt und erneut angehängt wird, über die Argumente gespeichert werden, ähnlich wie bundlesbei Intents.


9

Wenn Sie Parameter für eine Klasse verwenden. Versuche dies

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

5
Dies ist eigentlich ein schlechter Vorschlag. Sobald das Fragment von a neu erstellt wurde FragmentManager, verlieren Sie mSomeInstance.
Jaroslaw Mytkalyk

Einverstanden, sollte SomeClass paketierbar sein und mit setArguments ()
Jake_

1

Ich denke, es gibt keinen Unterschied zwischen dem statischen Konstruktor und zwei Konstruktoren (leerer und parametrisierter Konstruktor, der Argumente im Argumentbündel eines Fragments speichert). Diese Faustregel wurde höchstwahrscheinlich erstellt, um die Wahrscheinlichkeit zu verringern, dass vergessen wird, den Konstruktor ohne Argumente in Java zu implementieren , die nicht implizit generiert wird, wenn eine Überlastung vorliegt.

In meinen Projekten verwende ich Kotlin und implementiere Fragmente mit einem primären Konstruktor ohne Argumente und einem sekundären Konstruktor für Argumente, die sie nur in einem Bündel speichern und als Fragmentargumente festlegen. Alles funktioniert einwandfrei.


0

Wenn das Fragment nach der Konfigurationsänderung nicht standardmäßige Konstruktoren verwendet, verliert das Fragment alle Daten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.