Почему я хочу избегать конструкторов не по умолчанию в фрагментах?

Я создаю приложение с 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;
    }....

Без использования конструктора, отличного от стандартного?

Ответ 1

Сделайте объект пакета и вставьте свои данные (в этом примере ваш объект Category). Будьте осторожны, вы не можете передать этот объект прямо в комплект, если он не сериализуется. Я думаю, что лучше построить свой объект во фрагменте и поместить в комплект только идентификатор или что-то еще. Это код для создания и присоединения пакета:

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

После этого в данных доступа к фрагменту:

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

Что все.

Ответ 2

Кажется, что ни один из ответов на самом деле не отвечает "зачем использовать пакет для передачи параметров, а не нестандартных конструкторов"

Причина, по которой вы должны передавать параметры через пакет, заключается в том, что когда система восстанавливает fragment (например, при изменении конфигурации), она автоматически восстанавливает ваш bundle.

Обратные вызовы, такие как onCreate или onCreateView, должны читать параметры из bundle - таким образом вы гарантированно вернете состояние fragment правильно в том же состоянии, в котором был инициализирован fragment с ( обратите внимание, что это состояние может отличаться от onSaveInstanceState bundle, которое передается в onCreate/onCreateView)

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

Ответ 3

В вашем 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, прикрепленные к Intent s.

Ответ 4

Если вы используете параметр для некоторого класса. попробуйте это

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

Ответ 5

Я использовал метод, и он работает!

public FragmentHome() {
    // Required empty public constructor
}

public void FragmentHomeConstructor(Context context, String stringBundle) {
    mContext = context;
    mStringBundle = stringBundle;
}

Сделайте это методом фрагмента oncreate(), чтобы получить контекст без каких-либо ошибок!

mContext = this.getActivity();

В oncreate() метод вашей деятельности:

FragmentHome fragmentHome = new FragmentHome();
fragmentHome.FragmentHomeConstructor(mContext, mStringBundle);

Ответ 6

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

В моих проектах я использую Kotlin и реализую фрагменты с первичным конструктором no-arg и вторичным конструктором для аргументов, которые просто хранят их в комплекте и задают в качестве аргументов фрагмента, все работает нормально.