Dlaczego chcę unikać fragmentów konstruktorów innych niż domyślne?

173

Tworzę aplikację za pomocą Fragmentsiw jednym z nich utworzyłem konstruktor inny niż domyślny i otrzymałem to ostrzeżenie:

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

Czy ktoś może mi powiedzieć, dlaczego to nie jest dobry pomysł?

Czy możesz również zasugerować, jak mógłbym to osiągnąć:

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

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

Bez użycia konstruktora innego niż domyślny?

BlackHatSamurai
źródło
3
Nie, to nie pomaga. Nie odpowiedzieli na moje pytanie. Ale mimo wszystko dziękuję :)
BlackHatSamurai
31
@BlaineOmega W szczególności ten: stackoverflow.com/a/11602478/321697 zdecydowanie odpowiada na twoje pytanie. W przypadku zmiany orientacji lub innego zdarzenia, które powoduje ponowne utworzenie fragmentu, system Android używa domyślnego konstruktora, a także pakietu przekazanego jako argument. Jeśli używasz konstruktora niestandardowego, gdy tylko fragment zostanie odtworzony z powodu jednego z tych zdarzeń, wszystko, co zrobiłeś w konstruktorze niestandardowym, zostanie utracone.
Kevin Coppock
1
Dzięki, ale to wyjaśnia dlaczego, ale nie jak.
BlackHatSamurai
Jest to omówione w pierwszym i drugim linku w moim oryginalnym komentarzu.
CommonsWare,

Odpowiedzi:

110

Utwórz obiekt pakietu i wstaw swoje dane (w tym przykładzie Twój Categoryobiekt). Uważaj, nie możesz przekazać tego obiektu bezpośrednio do pakietu, chyba że można go serializować. Myślę, że lepiej jest zbudować obiekt we fragmencie i umieścić w pakiecie tylko identyfikator lub coś innego. Oto kod służący do tworzenia i dołączania pakietu:

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

Następnie w danych dostępu do fragmentów:

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

To wszystko.

nistv4n
źródło
3
jak przekazać przedmiot? Chcę przekazać obiekt kontekstu lub inny obiekt.
Adil Malik
12
Pakiety mogą zawierać zserializowane obiekty Java, a także Parcelableobiekty. Ponadto, nie należy zdać Context, ponieważ informacje te można uzyskać za pośrednictwem fragmentu w getActivity()metodzie .
krakatoa
We fragmencie gdzie to zrobić Type value = getArguments().getType("key");?
Muhammad Babar
4
@Muhammad Babar: Na twoim miejscu dodałbym to do newInstance()metody. Na przykład: public static FragmentName newInstance(your variables){}. Zgodnie z zaleceniami dokumentacji Androida nie twórz konstruktora z parametrami, ponieważ domyślny (bez parametrów) zostanie wywołany automatycznie po restarcie Twojego fragmentu.
nistv4n
@MuhammadBabar onCreateView jest OK
chanjianyi
272

Wygląda na to, że żadna z odpowiedzi nie odpowiada „po co używać pakietu do przekazywania parametrów zamiast konstruktorów innych niż domyślne”

Powodem, dla którego powinieneś przekazywać parametry przez pakiet, jest to, że gdy system przywróci plik fragment(np. Przy zmianie konfiguracji), automatycznie przywrócibundle .

Wywołania zwrotne, takie jak onCreatelub onCreateViewpowinny odczytywać parametry z bundle- w ten sposób masz gwarancję przywrócenia stanu fragmentprawidłowego do tego samego stanu, w jakim fragmentzostał zainicjowany (pamiętaj, że ten stan może się różnić od tego, onSaveInstanceState bundlektóry jest przekazywany doonCreate/onCreateView )

Zalecenie stosowania newInstance()metody statycznej jest tylko zaleceniem. Możesz użyć konstruktora innego niż domyślny, ale upewnij się, że parametry inicjalizacji zostały wypełnione w bundletreści tego konstruktora. I przeczytaj te parametry w metodach onCreate()lub onCreateView().

numan salati
źródło
2
Dobrze wyjaśnione. Dzięki. Gdybym to ja zadał pytanie, dałbym ci zaznaczenie
Karue Benson Karue
5
Nie możesz już używać konstruktora innego niż domyślny (z jakiegokolwiek powodu) .... powoduje to błąd kompilatora (wcześniej było to ostrzeżenie).
MPavlak
51

Twój Fragmentnie powinny mieć konstruktorów z powodu, jak FragmentManagerinstancję go. Powinieneś mieć newInstance()zdefiniowaną metodę statyczną z potrzebnymi parametrami, a następnie spakować je i ustawić jako argumenty fragmentu, do których możesz później uzyskać dostęp za pomocą Bundleparametru.

Na przykład:

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

Przeczytaj te argumenty pod adresem onCreate:

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

    //...
}

W ten sposób, jeśli zostanie odłączony i ponownie dołączony, stan obiektu może być przechowywany przez argumenty, podobnie jak bundlesdołączony doIntent s.

Asaf Pinhassi
źródło
9

Jeśli używasz parametru dla jakiejś klasy. Spróbuj tego

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}
김동기
źródło
5
To właściwie zła sugestia. Gdy fragment zostanie ponownie utworzony przez a FragmentManager, utracisz mSomeInstance.
Yaroslav Mytkalyk
Zgoda, SomeClass powinno być możliwe do spakowania i przechowywane w pakiecie za pomocą setArguments ()
Jake_
1

Myślę, że nie ma różnicy między konstruktorem statycznym a dwoma konstruktorami (pustym i sparametryzowanym, który przechowuje argumenty w pakiecie argumentów fragmentu), najprawdopodobniej ta praktyczna reguła została stworzona w celu zmniejszenia prawdopodobieństwa zapomnienia o implementacji konstruktora bezargumentowego w Javie , który nie jest generowany niejawnie, gdy występuje przeciążenie.

W moich projektach używam Kotlina i implementuję fragmenty z głównym konstruktorem bez argonu i konstruktorem pomocniczym dla argumentów, który po prostu przechowuje je w paczce i ustawia jako argumenty Fragment, wszystko działa dobrze.

Pavlus
źródło
0

Jeśli fragment używa konstruktorów innych niż domyślne, po zmianie konfiguracji fragment utraci wszystkie dane.

Akop Vardanian
źródło