Чому я хочу уникати конструкторів за замовчуванням у фрагментах?


173

Я створюю додаток за допомогою Fragmentsі в одному з них я створив конструктор, який не використовується за замовчуванням, і отримав це попередження:

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

Може хтось скаже мені, чому це не гарна ідея?

Чи можете ви також підказати, як я це досяг:

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

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

Без використання конструктора за замовчуванням?



3
Ні, це не допомагає. Вони не відповіли на моє запитання. Але все-таки дякую :)
BlackHatSamurai

31
@BlaineOmega Насправді саме цей: stackoverflow.com/a/11602478/321697 безумовно відповідає на ваше запитання. Під час зміни орієнтації або іншої події, яка викликає відтворення фрагмента, Android використовує конструктор за замовчуванням, а також пакет, переданий як аргумент. Якщо ви користуєтеся спеціальним конструктором, то, як тільки фрагмент буде відтворений через одну з цих подій, все, що ви робили в спеціальному конструкторі, втрачається.
Кевін Коппок

1
Дякую, але це відповідає на те, чому, але не як.
BlackHatSamurai

Це висвітлено в першому та другому посиланнях мого оригінального коментаря.
CommonsWare

Відповіді:


110

Складіть об’єкт групи та вставте свої дані (у цьому прикладі ваш Categoryоб’єкт). Будьте обережні, ви не можете передавати цей об'єкт безпосередньо в пакет, якщо тільки це не можна серіалізувати. Я думаю, що краще зібрати свій об’єкт на фрагменті, а в комплект вкласти лише ідентифікатор чи щось інше. Це код для створення та додавання пакета:

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

Після цього у своєму фрагменті отримайте доступ до даних:

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

Це все.


3
як передати об’єкт? Я хочу передати контекстний об’єкт або будь-який інший об'єкт.
Аділ Малик

12
Пакети можуть нести серіалізовані об'єкти Java, а також Parcelableоб'єкти. Крім того, ви не повинні передавати номер Context, тому що до цієї інформації можна отримати getActivity()метод фрагмента .
krakatoa

У фрагменті, де це зробити Type value = getArguments().getType("key");?
Мухаммед Бабар

4
@ Мухаммед Бабар: Якби я був ти, я би додав це до newInstance()методу. Наприклад: public static FragmentName newInstance(your variables){}. Як рекомендує документація на Android, не створюйте конструктор з параметрами, тому що за замовчуванням (без параметрів) буде викликано автоматично після перезавантаження вашого фрагмента.
nistv4n

@MuhammadBabar onCreateView в порядку
chanjianyi

272

Схоже, жодна з відповідей насправді не відповідає "чому використовувати пакет для передачі параметрів, а не конструктори за замовчуванням"

Причина, чому вам слід передавати параметри через пакет, полягає в тому, що коли система відновить fragment(наприклад, при зміні конфігурації), вона автоматично відновить ваш bundle.

Зворотні виклики люблять onCreateабо onCreateViewповинні читати параметри з bundle- таким чином ви гарантовано відновите стан fragmentправильно до того самого стану, з яким fragmentбуло ініціалізовано (зауважте, що цей стан може відрізнятися від того, onSaveInstanceState bundleщо передається в onCreate/onCreateView)

Рекомендація щодо використання статичного newInstance()методу - лише рекомендація. Ви можете використовувати конструктор, що не використовується за замовчуванням, але переконайтеся, що ви заповнюєте параметри ініціалізації bundleвсередині тіла цього конструктора. І прочитайте ці параметри в методах onCreate()або onCreateView()методах.


2
Добре пояснено. Дякую. Якби я хтось задав це питання, я би поставив вам галочку
Karue Benson Karue

5
Більше не можна використовувати конструктор за замовчуванням (з будь-якої причини) .... це дає помилку компілятора (раніше була попередженням).
МПавлак

51

У вас Fragmentне повинно бути конструкторів через те, як це FragmentManagerстворюється. Ви повинні мати newInstance()статичний метод, визначений необхідними параметрами, а потім зв’язати їх і встановити як аргументи фрагмента, до якого ви згодом можете отримати доступ із Bundleпараметром.

Наприклад:

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

І прочитайте ці аргументи на onCreate:

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

    //...
}

Таким чином, якщо їх від'єднати і повторно приєднати, стан об'єкта може зберігатися через аргументи, як і bundlesприєднаний до Intents.


9

Якщо ви використовуєте параметр для якогось класу. спробуйте це

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

5
Це насправді погана пропозиція. Як тільки фрагмент буде створений a FragmentManager, ви втратите mSomeInstance.
Ярослав Миткалик

Погоджено, SomeClass повинен бути парцельований і зберігатися в пакеті, використовуючи setArguments ()
Jake_

1

Я думаю, немає різниці між статичним конструктором та двома конструкторами (порожній і параметризований, який зберігає аргументи в пакет аргументів фрагмента), швидше за все, це правило створено для зменшення ймовірності забути застосувати конструктор no-arg в Java , що неявно генерується при наявності перевантаження.

У своїх проектах я використовую Kotlin і реалізую фрагменти з первинним конструктором no-arg та вторинним конструктором для аргументів, який просто зберігає їх у пакет і встановлює як аргументи Fragment, все працює добре.


0

Якщо фрагмент використовує конструктори за замовчуванням після зміни конфігурації, фрагмент втратить усі дані.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.