Best Practice zum Instanziieren eines neuen Android-Fragments

Lesezeit: 10 Minuten

Best Practice zum Instanziieren eines neuen Android Fragments
Graham Smith

Ich habe zwei allgemeine Praktiken gesehen, um ein neues Fragment in einer Anwendung zu instanziieren:

Fragment newFragment = new MyFragment();

und

Fragment newFragment = MyFragment.newInstance();

Die zweite Option verwendet eine statische Methode newInstance() und allgemein enthält die folgende Methode.

public static Fragment newInstance() 
{
    MyFragment myFragment = new MyFragment();
    return myFragment;
}

Zuerst dachte ich, der Hauptvorteil sei die Tatsache, dass ich die Methode newInstance() überladen könnte, um beim Erstellen neuer Instanzen eines Fragments Flexibilität zu bieten – aber ich könnte dies auch tun, indem ich einen überladenen Konstruktor für das Fragment erstelle.

Habe ich etwas verpasst?

Was sind die Vorteile eines Ansatzes gegenüber dem anderen? Oder ist es nur gute Praxis?

  • Wenn es Parameter gibt, gibt es keine Wahl, und dies wird hier ausführlich beantwortet. Dennoch bleibt die Frage nach einer argumentlosen Konstruktion des Fragments.

    – rts

    7. Dezember 2015 um 10:51 Uhr


  • Nachdem ich etwas über Fabrikmuster gelernt hatte und wie eine aufrufende Klasse, die kein Objekt selbst instanziiert, dabei hilft, sie zu entkoppeln, dachte ich, dass dies eine Stärke der Methode newInstance() wäre. Liege ich da falsch? Ich habe dieses spezielle Argument nicht als Vorteil gesehen.

    – Mobile Anwendungen

    2. November 2016 um 2:30 Uhr


1646768592 846 Best Practice zum Instanziieren eines neuen Android Fragments
yydl

Wenn Android beschließt, Ihr Fragment später neu zu erstellen, ruft es den Konstruktor ohne Argumente Ihres Fragments auf. Das Überladen des Konstruktors ist also keine Lösung.

Abgesehen davon besteht die Möglichkeit, Inhalte an Ihr Fragment zu übergeben, damit sie verfügbar sind, nachdem ein Fragment von Android neu erstellt wurde, darin, ein Bundle an die zu übergeben setArguments Methode.

Wenn wir also zum Beispiel eine ganze Zahl an das Fragment übergeben wollten, würden wir so etwas verwenden:

public static MyFragment newInstance(int someInt) {
    MyFragment myFragment = new MyFragment();

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    myFragment.setArguments(args);

    return myFragment;
}

Und später im Fragment onCreate() Sie können auf diese Ganzzahl zugreifen, indem Sie Folgendes verwenden:

getArguments().getInt("someInt", 0);

Dieses Bundle ist auch dann verfügbar, wenn das Fragment irgendwie von Android neu erstellt wird.

Beachten Sie auch: setArguments kann nur aufgerufen werden, bevor das Fragment an die Aktivität angehängt wird.

Dieser Ansatz ist auch in der Android-Entwicklerreferenz dokumentiert: https://developer.android.com/reference/android/app/Fragment.html

  • @Vlasto leider können statische Methoden nicht überschrieben werden.

    – AJD

    5. Februar 2013 um 15:08 Uhr

  • @yydl Ich glaube, mir fehlt hier etwas, könnten Sie hier nicht trotzdem einen Konstruktor verwenden, der das Bundle erstellt und setArguments() aufruft, da es nur von Ihrem Code aufgerufen wird (und nicht, wenn Android Ihren neu erstellt). Fragment)?

    – Mike Tunnicliffe

    30. März 2013 um 13:48 Uhr

  • @mgibson Du Muss Verwenden Sie ein Bündel, wenn Sie möchten, dass die Daten verfügbar sind, wenn das Fragment später neu erstellt wird.

    – yydl

    30. Juni 2013 um 2:41 Uhr

  • GEZWUNGEN zu sein, einen Konstruktor ohne Argumente für Fragmente zu erstellen, ist möglicherweise der größte Fallstrick in der gesamten Programmierung. Es erzwingt einen vollständigen Paradigmenwechsel bei der Objekterstellung und -initialisierung. Wenn Sie neu bei Android sind und über diesen Thread gestolpert sind, lesen Sie bitte die obige Antwort immer und immer wieder.

    – rmirabelle

    2. August 2013 um 15:20 Uhr

  • Dieser Behauptung würde ich widersprechen. Erstens ist die Typsicherheit ein Problem der Sprache, nicht des Frameworks. Zweitens betritt das Framework meiner Meinung nach den Bereich der „Dinge, die Ihre API niemals tun darf“. Wenn ich die Kongressbibliothek an meinen Fragmentkonstruktor übergeben möchte, sollte ich das dürfen. Der “no-args”-Konstruktorvertrag tötet im Grunde die Verwendung von Abhängigkeitsinjektionen in Fragmenten – großer Igitt.

    – rmirabelle

    28. Juli 2014 um 14:14 Uhr

1646768593 258 Best Practice zum Instanziieren eines neuen Android Fragments
500865

Der einzige Vorteil bei der Verwendung der newInstance() die ich sehe sind die folgenden:

  1. Sie haben einen einzigen Ort, an dem alle vom Fragment verwendeten Argumente gebündelt werden können, und Sie müssen den folgenden Code nicht jedes Mal schreiben, wenn Sie ein Fragment instanziieren.

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    args.putString("someString", someString);
    // Put any other arguments
    myFragment.setArguments(args);
    
  2. Es ist eine gute Möglichkeit, anderen Klassen mitzuteilen, welche Argumente es hat erwartet um treu zu arbeiten (obwohl Sie in der Lage sein sollten, Fälle zu behandeln, wenn keine Argumente in der Fragmentinstanz gebündelt sind).

Ich nehme also an, dass ich eine Statik verwende newInstance() Ein Fragment zu instanziieren ist eine bewährte Vorgehensweise.

  • 1) Wie unterscheidet sich das davon, die Logik in einen Konstruktor zu stecken? Beides sind Einzelstellen, an denen Sie diese Logik einbeziehen. 2) Wie unterscheiden sich Parameter einer statischen Fabrik von Parametern eines Konstruktors? Beide sagen, welche Argumente erwartet werden. Mein Punkt ist, dass es sicher ein anderes Paradigma ist, aber dies hat keinen klaren Vorteil gegenüber der Verwendung von Konstruktoren.

    – RJ Cuthbertson

    11. August 2016 um 16:28 Uhr

  • Sie können keine benutzerdefinierten Konstruktoren für fragment verwenden. Framework verwendet den No-Argument-Konstruktor zum Wiederherstellen von Fragmenten.

    – 500865

    11. August 2016 um 18:53 Uhr

  • Ja, da stimme ich dir zu. Ich sage konzeptionell, dass es keinen Vorteil hat, das statische Fabrikmuster zu verwenden, anstatt überladene Konstruktoren zu verwenden, und umgekehrt. Beide Ihrer Punkte sind in beiden Mustern gültig; Es gibt keinen Vorteil, einen über dem anderen zu verwenden. Android zwingt Sie dazu, das statische Fabrikmuster zu verwenden – aber es bringt keinen Vorteil, das eine oder andere zu verwenden.

    – RJ Cuthbertson

    11. August 2016 um 20:45 Uhr

  • @RJCuthbertson Ein möglicher Vorteil wäre die Fähigkeit zum Erstellen und Zurückgeben Unterklassen der Klasse der statischen Fabrikmethode, dh um eine geeignete Unterklasse für die Situation zurückzugeben.

    – dringendx

    2. September 2017 um 11:41 Uhr

1646768593 173 Best Practice zum Instanziieren eines neuen Android Fragments
drlue

Es gibt auch einen anderen Weg:

Fragment.instantiate(context, MyFragment.class.getName(), myBundle)

  • Ich habe dies mit der Support-Bibliothek versucht, aber in onCreateView (in meinem Fragment) war das übergebene Bundle null, also habe ich mich für die Option setArguments/getArguments entschieden und es hat funktioniert (für alle, die dies lesen).

    – Jrop

    28. August 2013 um 15:49 Uhr

  • Interessant, diesen Ansatz habe ich noch nicht gesehen. Hat es Vorteile gegenüber anderen Ansätzen zum Instanziieren eines Fragments?

    – IgorGanapolsky

    12. November 2013 um 16:45 Uhr

  • Von dem Entwicklerdokumente, instantiate() Creates a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.

    – Brian Bowmann

    9. Februar 2014 um 16:13 Uhr

  • Obwohl sie dasselbe wie das Aufrufen eines leeren Konstruktors erwähnt haben. “args.setClassLoader(f.getClass().getClassLoader());” wird darunter für Bundle-Argumente aufgerufen

    – Gökhan Barış Aker

    17. März 2014 um 21:35 Uhr

  • instantiate(...) Methoden sind veraltet in API 28. Ich glaube auch nicht, dass es ein guter Ansatz ist, Fragmente zu erstellen.

    – Yekta Sarıoğlu

    16. November 2020 um 20:20 Uhr

1646768593 721 Best Practice zum Instanziieren eines neuen Android Fragments
xyz

Während @yydl einen zwingenden Grund dafür angibt, warum die newInstance Methode ist besser:

Wenn Android beschließt, Ihr Fragment später neu zu erstellen, ruft es den Konstruktor ohne Argumente Ihres Fragments auf. Das Überladen des Konstruktors ist also keine Lösung.

es ist immer noch möglich, a zu verwenden Konstrukteur. Um zu sehen, warum das so ist, müssen wir zuerst sehen, warum die obige Problemumgehung von Android verwendet wird.

Bevor ein Fragment verwendet werden kann, wird eine Instanz benötigt. Android ruft an YourFragment() (der keine Argumente Konstruktor), um eine Instanz des Fragments zu erstellen. Hier wird jeder überladene Konstruktor, den Sie schreiben, ignoriert, da Android nicht wissen kann, welcher verwendet werden soll.

Während der Lebensdauer einer Aktivität wird das Fragment wie oben erstellt und mehrmals von Android zerstört. Das bedeutet, dass Daten, die Sie in das Fragmentobjekt selbst einfügen, verloren gehen, sobald das Fragment zerstört wird.

Um dies zu umgehen, fordert Android Sie auf, Daten mit a zu speichern Bundle (Berufung setArguments()), auf die dann zugegriffen werden kann YourFragment. Streit bundles sind durch Android geschützt und daher garantiert hartnäckig.

Eine Möglichkeit, dieses Bundle festzulegen, ist die Verwendung eines statischen newInstance Methode:

public static YourFragment newInstance (int data) {
    YourFragment yf = new YourFragment()
    /* See this code gets executed immediately on your object construction */
    Bundle args = new Bundle();
    args.putInt("data", data);
    yf.setArguments(args);
    return yf;
}

Allerdings ein Konstruktor:

public YourFragment(int data) {
    Bundle args = new Bundle();
    args.putInt("data", data);
    setArguments(args);
}

kann genau das gleiche wie die newInstance Methode.

Dies würde natürlich fehlschlagen und ist einer der Gründe, warum Android möchte, dass Sie die verwenden newInstance Methode:

public YourFragment(int data) {
    this.data = data; // Don't do this
}

Zur weiteren Erläuterung hier die Fragment-Klasse von Android:

/**
 * Supply the construction arguments for this fragment.  This can only
 * be called before the fragment has been attached to its activity; that
 * is, you should call it immediately after constructing the fragment.  The
 * arguments supplied here will be retained across fragment destroy and
 * creation.
 */
public void setArguments(Bundle args) {
    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

Beachten Sie, dass Android Sie auffordert, die Argumente festzulegen nur beim Bau und garantiert, dass diese erhalten bleiben.

BEARBEITEN: Wie in den Kommentaren von @JHH erwähnt, stellt Java Ihr Fragment nicht mit einem bereit, wenn Sie einen benutzerdefinierten Konstruktor bereitstellen, der einige Argumente erfordert nein arg Standardkonstruktor. Dazu müssten Sie also a definieren nein arg Konstruktor, das ist Code, den Sie mit dem vermeiden könnten newInstance Fabrikmethode.

BEARBEITEN: Android erlaubt die Verwendung eines überladenen Konstruktors für Fragmente nicht mehr. Sie müssen die verwenden newInstance Methode.

Best Practice zum Instanziieren eines neuen Android Fragments
Raffols

Etwas kotlin Code:

companion object {
    fun newInstance(first: String, second: String) : SampleFragment {
        return SampleFragment().apply {
            arguments = Bundle().apply {
                putString("firstString", first)
                putString("secondString", second)
            }
        }
    }
}

Und Sie können Argumente damit bekommen:

val first: String by lazy { arguments?.getString("firstString") ?: "default"}
val second: String by lazy { arguments?.getString("secondString") ?: "default"}

  • Ist es am besten, die zu verwenden @JvmStatic Anmerkung? @JvmStatic fun newInstance(bundle: Bundle) = SomeFragment().apply { arguments = bundle }

    – Adam Hurwitz

    19. Juli 2020 um 19:30 Uhr

1646768594 494 Best Practice zum Instanziieren eines neuen Android Fragments
Ziem

ich nicht zustimmen mit yydi antwort sagen:

Wenn Android beschließt, Ihr Fragment später neu zu erstellen, ruft es den Konstruktor ohne Argumente Ihres Fragments auf. Das Überladen des Konstruktors ist also keine Lösung.

Ich denke, es ist eine Lösung und eine gute, genau aus diesem Grund wurde es von der Java-Kernsprache entwickelt.

Es stimmt, dass ein Android-System Ihr System zerstören und neu erstellen kann Fragment. Sie können also Folgendes tun:

public MyFragment() {
//  An empty constructor for Android System to use, otherwise exception may occur.
}

public MyFragment(int someInt) {
    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    setArguments(args);
}

Es wird Ihnen erlauben zu ziehen someInt von getArguments() letzteres auf, auch wenn die Fragment wurde vom System neu erstellt. Dies ist eine elegantere Lösung als static Konstrukteur.

Meiner Meinung nach static Konstruktoren sind nutzlos und sollten nicht verwendet werden. Sie werden Sie auch einschränken, wenn Sie dies in Zukunft erweitern möchten Fragment und fügen Sie dem Konstruktor weitere Funktionen hinzu. Mit static Konstruktor können Sie dies nicht tun.

Aktualisieren:

Android hat eine Inspektion hinzugefügt, die alle nicht standardmäßigen Konstruktoren mit einem Fehler kennzeichnet.
Ich empfehle, es aus den oben genannten Gründen zu deaktivieren.

  • Ist es am besten, die zu verwenden @JvmStatic Anmerkung? @JvmStatic fun newInstance(bundle: Bundle) = SomeFragment().apply { arguments = bundle }

    – Adam Hurwitz

    19. Juli 2020 um 19:30 Uhr

Best Practice zum Instanziieren eines neuen Android Fragments
Gunhan

Die beste Vorgehensweise zum Instanziieren von Fragmenten mit Argumenten in Android besteht darin, eine statische Factory-Methode in Ihrem Fragment zu haben.

public static MyFragment newInstance(String name, int age) {
    Bundle bundle = new Bundle();
    bundle.putString("name", name);
    bundle.putInt("age", age);

    MyFragment fragment = new MyFragment();
    fragment.setArguments(bundle);

    return fragment;
}

Sie sollten es vermeiden, Ihre Felder mit der Instanz eines Fragments zu setzen. Denn wann immer das Android-System Ihr Fragment neu erstellt, wenn es das Gefühl hat, dass das System mehr Speicher benötigt, wird es Ihr Fragment neu erstellen, indem es den Konstruktor ohne Argumente verwendet.

Weitere Informationen finden Sie unter Best Practice zum Instanziieren von Fragmenten mit Argumenten Hier.

977370cookie-checkBest Practice zum Instanziieren eines neuen Android-Fragments

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy