Переменные участника vs setArguments в фрагментах

Я заметил, что в справочной системе Android для фрагментов (особенно DialogFragment) они делают пару вещей, отличных от того, что я Ожидайте:

1). Используйте метод public static foo newInstance(), а не конструктор.
2). Передайте значения в onCreateDialog, используя setArguments, а не переменные-члены.

Я читал, что newInstance кажется предпочтительным при использовании отражения. Однако я действительно не понимаю, почему они передают параметры через комплект. Я бы использовал, если бы переменные-члены были бы более безопасными (не используя строку для извлечения из карты) и имели бы меньшие накладные расходы.

Любые мысли?

Ответ 1

Я также наткнулся на это и нашел несколько преимуществ использования аргументов Bundle над полями экземпляра:

  • Если в системе Bundle система Android знает об этом и может создать и уничтожить ваш Fragment (используя обязательный конструктор без параметров/по умолчанию и обычные методы жизненного цикла) и просто перейдите в набор аргументов снова, Таким образом, никакие аргументы не теряются при низком заряде памяти или изменении ориентации (это часто поражает меня при первом развертывании на реальном устройстве после разработки в менее вращающемся эмуляторе).

  • Вы можете просто передать дополнительные функции Bundle Activity as-is в Fragment, встроенные в макет; например Я часто использую это, когда у меня есть Activity, который отображает Fragment "fullscreen" и нуждается в некотором идентификаторе (или ContentProvider URI), чтобы знать, что показывать/делать. Иногда я даже добавляю больше вещей в Bundle (или копию), прежде чем передать его, например.

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      if (savedInstanceState == null) { // not a re-creation
        final Bundle args = new Bundle(getIntent().getExtras());
        args.putInt(CoverImageFragment.BACKGROUND_RESOURCE, android.R.color.black);
        final Fragment fragment = CoverImageFragment.newInstance(args);
        getSupportFragmentManager()
          .beginTransaction()
          .add(android.R.id.content, fragment)
          .commit();
      }
    }
    
  • Он поддерживает способ создания Fragment рядом с Activity, т.е. Bundle как "входные параметры, без исключений".

Что касается недостатков, о которых вы упомянули:

  • Я думаю, что накладные расходы минимальны, потому что вы, скорее всего, не будете запрашивать Bundle в узком цикле, поэтому вы получаете данные аргумента один раз в onCreate(), onViewCreate() и т.д. isn ' Это плохо.

  • Для безопасности типов Bundle имеет все различные методы getXXXX() и даже перегрузки для предоставления значения по умолчанию, если что-то отсутствует/необязательно:)

Что касается методов newInstance(), я думаю о них как о простом способе инкапсуляции вызовов new и setArguments() для моего Fragment; Иногда я предоставляю дополнительный MyFragment newInstance(String singleIdOfWhatToDisplay), который создает как Bundle, так и Fragment за один раз и возвращает экземпляр Fragment, готовый к использованию.

Ответ 2

Я нашел, что это ВЫСОКО-путающая проблема (одна из многих, которая портит пейзаж Android).

setArguments() - обходной путь для Android очень бесполезно, чтобы иметь конструктор без параметров, доступный для фрагментов.

Мое замешательство началось в волнах. Во-первых, методы, которые вы, естественно, переопределяете в Fragment (например, onCreate, onCreateView), получают параметр Bundle, который представляет savedInstanceState вашего Fragment. Это состояние экземпляра, по-видимому, имеет НИЧЕГО что бы вы ни делали со значениями, которые вы храните через setArguments() и извлекаете через getArguments(). Оба используют Bundle, и те, и другие Bundles, вероятно, будут доступны в рамках одного и того же переопределенного метода, и не имеют ничего общего друг с другом.

Во-вторых, непонятно, как Android использует setArguments(). Android вызывает ваш конструктор без параметров, чтобы перестроить ваш Fragment при повороте, но, по-видимому, ТАКЖЕ будет вызывать любой метод setArguments(), который последний раз вызывался при построении Fragment.

Да????

Удивительно, но верно. Все это создает Bundles с безумием setArguments() для компенсации необходимости конструктора Fragment.

Короче говоря, я использую статический метод newInstance для создания Fragment.

public MyFragment() {
    //satisfy Android
}

public static MyFragment newInstance(long record_id) {
    Log.d("MyFragment", "Putting " + record_id + " into newInstance");
    MyFragment f = new MyFragment();
    Bundle args = new Bundle();
    args.putLong("record_id", record_id);
    f.setArguments(args);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /**
     * Perform an immediate check of arguments,
     * which ARE NOT the same as the bundle used
     * for saved instance state.
     */
    Bundle args = getArguments();
    if(args != null) {
        record_id = args.getLong("record_id");
        Log.d("MyFragment", "found record_id of " + String.valueOf(record_id));
    }
    if(savedInstanceState != null) {
        //now do something with savedInstanceState
    }
}

Ответ 3

Я новичок в программировании на Android, но это мое текущее понимание проблемы:

Конструктор для фрагментов не может иметь никаких параметров. Когда ваша деятельность приостановлена, ваш фрагмент может быть выпущен. Прежде чем ваша деятельность будет возобновлена, система создаст новую версию вашего фрагмента, вызывающего конструктор. Если используется нестандартный конструктор, как Android должен знать, что типы и значения для аргументов для вашего конструктора фрагментов?

Я не верю, что пакет выпущен. Пакет поддерживается точно так, чтобы его можно было вернуть обратно в ваш фрагмент после его создания с помощью конструктора по умолчанию.

Филипп Рейхарт избегал этого в своем посте (на самом деле больше, чем ускользнул).

Ответ 4

Просто хочу добавить еще один недостаток аргументов в том, что вам нужно динамически создавать фрагменты. Поскольку аргументы не работают очень хорошо, если вы создаете из xml. И я действительно ненавижу это.