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?

BlackHatSamurai
quelle
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.

nistv4n
quelle
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().

numan salati
quelle
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.

Asaf Pinhassi
quelle
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;
}
김동기
quelle
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.

Pavlus
quelle
0

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

Akop Vardanian
quelle