Создание фрагмента: конструктор vs newInstance()

Недавно я устал от необходимости постоянно знать ключи String для передачи аргументов в Bundles при создании my Fragments. Поэтому я решил создать конструкторы для моего Fragments, которые будут принимать параметры, которые я хотел установить, и поместить эти переменные в Bundles с правильными клавишами String, поэтому устраняя необходимость в других Fragments и Activities нужно знать эти ключи.

public ImageRotatorFragment() {
    super();
    Log.v(TAG, "ImageRotatorFragment()");
}

public ImageRotatorFragment(int imageResourceId) {
    Log.v(TAG, "ImageRotatorFragment(int imageResourceId)");

    // Get arguments passed in, if any
    Bundle args = getArguments();
    if (args == null) {
        args = new Bundle();
    }
    // Add parameters to the argument bundle
    args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
    setArguments(args);
}

И затем я вывожу эти аргументы, как обычно.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.v(TAG, "onCreate");

    // Set incoming parameters
    Bundle args = getArguments();
    if (args != null) {
        mImageResourceId = args.getInt(KEY_ARG_IMAGE_RES_ID, StaticData.getImageIds()[0]);
    }
    else {
        // Default image resource to the first image
        mImageResourceId = StaticData.getImageIds()[0];
    }
}

Тем не менее, Линт принял решение об этом, заявив, что не имеет подклассов Fragment с конструкторами с другими параметрами, требуя, чтобы я использовал @SuppressLint("ValidFragment"), чтобы даже запустить приложение. Дело в том, что этот код работает отлично. Я могу использовать ImageRotatorFragment(int imageResourceId) или старый метод школы ImageRotatorFragment() и называть setArguments() вручную на нем. Когда Android нужно воссоздать фрагмент (изменение ориентации или низкая память), он вызывает конструктор ImageRotatorFragment(), а затем передает тот же аргумент Bundle с моими значениями, которые устанавливаются правильно.

Итак, я искал "предложенный" подход и вижу множество примеров, используя newInstance() для создания Fragments с параметрами, которые, похоже, делают то же самое, что и мой конструктор. Поэтому я сделал свой собственный, чтобы проверить его, и он работает так же безупречно, как и раньше, минус Линт, скулящий об этом.

public static ImageRotatorFragment newInstance(int imageResourceId) {
    Log.v(TAG, "newInstance(int imageResourceId)");

    ImageRotatorFragment imageRotatorFragment = new ImageRotatorFragment();

    // Get arguments passed in, if any
    Bundle args = imageRotatorFragment.getArguments();
    if (args == null) {
        args = new Bundle();
    }
    // Add parameters to the argument bundle
    args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
    imageRotatorFragment.setArguments(args);

    return imageRotatorFragment;
}

Я лично считаю, что использование конструкторов является гораздо более распространенной практикой, чем знание использовать newInstance() и передавать параметры. Я считаю, что вы можете использовать эту же конструкторскую технику с Activity, и Lint не будет жаловаться на это. Итак, в основном, мой вопрос: почему Google не хочет, чтобы вы использовали конструкторы с параметрами для Fragments?

Моя единственная догадка заключается в том, что вы не пытаетесь установить переменную экземпляра без использования Bundle, который не будет установлен, если воссоздается Fragment. Используя метод static newInstance(), компилятор не даст вам доступ к переменной экземпляра.

public ImageRotatorFragment(int imageResourceId) {
    Log.v(TAG, "ImageRotatorFragment(int imageResourceId)");

    mImageResourceId = imageResourceId;
}

Мне все еще не кажется, что этого достаточно, чтобы запретить использование параметров в конструкторах. Кто-нибудь еще знает об этом?

Ответ 1

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

factory шаблон метода используется довольно часто в современной разработке программного обеспечения.

Итак, в основном, мой вопрос: почему Google не хочет, чтобы вы использовали конструкторы с параметрами для фрагментов?

Вы ответили на свой вопрос:

Мое единственное предположение: вы не пытаетесь установить переменную экземпляра без использования Bundle, который не будет установлен, когда Fragment будет воссоздан.

Правильно.

Мне все еще не кажется, что этого достаточно, чтобы запретить использование параметров в конструкторах.

Добро пожаловать на Ваше мнение. Вы можете отключить эту проверку Lint либо на основе конструктора, либо на рабочем пространстве.

Ответ 2

Android только воссоздает фрагменты, которые он убивает, используя конструктор по умолчанию, поэтому любая инициализация, которую мы выполняем в дополнительных конструкторах, будет потеряна. Данные о состоянии будут потеряны.