Я видел две общие практики создания нового фрагмента в приложении:
Fragment newFragment = new MyFragment();
а также
Fragment newFragment = MyFragment.newInstance();
Второй вариант использует статический метод newInstance()
и обычно содержит следующий метод.
public static Fragment newInstance()
{
MyFragment myFragment = new MyFragment();
return myFragment;
}
Сначала я подумал, что главное преимущество заключается в том, что я могу перегрузить метод newInstance (), чтобы обеспечить гибкость при создании новых экземпляров фрагмента, но я мог бы также сделать это, создав перегруженный конструктор для фрагмента.
Я что-то пропустил?
Каковы преимущества одного подхода над другим? Или это просто хорошая практика?
android
android-fragments
Грэм Смит
источник
источник
Ответы:
Если Android решит воссоздать ваш фрагмент позже, он вызовет конструктор без аргументов вашего фрагмента. Таким образом, перегрузка конструктора не является решением.
С учетом вышесказанного, способ передать вещи в ваш фрагмент, чтобы они были доступны после повторного создания фрагмента в Android, - передать пакет
setArguments
методу.Так, например, если мы хотим передать целое число во фрагмент, мы будем использовать что-то вроде:
А позже во фрагменте
onCreate()
вы можете получить доступ к этому целому числу с помощью:Этот комплект будет доступен, даже если фрагмент каким-то образом воссоздан в Android.
Также обратите внимание:
setArguments
может быть вызван только до того, как фрагмент прикреплен к действию.Этот подход также задокументирован в справочнике разработчика Android: https://developer.android.com/reference/android/app/Fragment.html.
источник
Единственное преимущество в использовании,
newInstance()
которое я вижу, заключается в следующем:У вас будет единственное место, где все аргументы, используемые фрагментом, могут быть связаны, и вам не нужно будет писать код ниже каждый раз, когда вы создаете экземпляр фрагмента.
Это хороший способ сообщить другим классам, какие аргументы он ожидает для добросовестной работы (хотя вы должны иметь возможность обрабатывать случаи, если в экземпляре фрагмента нет связанных аргументов).
Итак, я считаю, что использование статики
newInstance()
для создания экземпляра фрагмента является хорошей практикой.источник
Есть и другой способ:
источник
instantiate()
Creates a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.
В то время как @yydl дает убедительную причину, почему
newInstance
метод лучше:все еще вполне возможно использовать конструктор . Чтобы понять, почему это так, сначала нам нужно понять, почему вышеуказанный обходной путь используется Android.
Перед использованием фрагмента необходим экземпляр. Android вызывает
YourFragment()
( конструктор без аргументов ) для создания экземпляра фрагмента. Здесь любой перегруженный конструктор, который вы напишите, будет игнорироваться, так как Android не может знать, какой из них использовать.Во время жизни действия фрагмент создается, как описано выше, и несколько раз уничтожается Android. Это означает, что если вы поместите данные в сам объект фрагмента, они будут потеряны после уничтожения фрагмента.
Чтобы обойти эту проблему, Android просит сохранить данные с помощью
Bundle
(вызоваsetArguments()
), к которому затем можно получить доступYourFragment
. Аргументыbundle
защищены Android, и, следовательно, гарантированно будут постоянными .Один из способов установить этот комплект - использовать статический
newInstance
метод:Тем не менее, конструктор:
может сделать то же самое, что и
newInstance
метод.Естественно, это не удастся, и это одна из причин, по которой Android хочет, чтобы вы использовали этот
newInstance
метод:Как дальнейшее объяснение, вот класс фрагментов Android:
Обратите внимание, что Android запрашивает, чтобы аргументы устанавливались только при конструировании, и гарантирует, что они будут сохранены.
РЕДАКТИРОВАТЬ : Как указано в комментариях @JHH, если вы предоставляете пользовательский конструктор, который требует некоторых аргументов, то Java не будет предоставлять ваш фрагмент конструктор по умолчанию без аргументов . Так что для этого потребуется определить конструктор без аргументов , то есть код, который вы могли бы избежать с помощью
newInstance
метода фабрики.РЕДАКТИРОВАТЬ : Android больше не позволяет использовать перегруженный конструктор для фрагментов. Вы должны использовать
newInstance
метод.источник
Я не согласен с yydi ответом :
Я думаю, что это хорошее решение, именно поэтому оно было разработано базовым языком Java.
Это правда, что система Android может уничтожить и воссоздать вашу
Fragment
. Так что вы можете сделать это:Это позволит вам вытащить
someInt
изgetArguments()
последних на, даже еслиFragment
были воссозданы системой. Это более элегантное решение, чемstatic
конструктор.По моему мнению,
static
конструкторы бесполезны и не должны использоваться. Также они будут ограничивать вас, если в будущем вы захотите расширить этоFragment
и добавить больше функциональности в конструктор. Сstatic
конструктором вы не можете сделать это.Обновить:
Android добавил проверку, которая помечает все конструкторы не по умолчанию с ошибкой.
Я рекомендую отключить его по причинам, указанным выше.
источник
Некоторый код котлина :
И вы можете получить аргументы с этим:
источник
Лучшая практика для копирования фрагментов с аргументами в Android - использовать статический метод фабрики в вашем фрагменте.
Вы должны избегать установки полей с экземпляром фрагмента. Потому что всякий раз, когда система Android воссоздает ваш фрагмент, если она чувствует, что системе требуется больше памяти, она будет воссоздавать ваш фрагмент, используя конструктор без аргументов.
Вы можете найти больше информации о наилучшей практике создания фрагментов с аргументами здесь.
источник
Поскольку вопросы о передовой практике, я бы добавил, что очень часто хорошая идея использовать гибридный подход для создания фрагмента при работе с некоторыми веб-сервисами REST.
Мы не можем передать сложные объекты, например некоторую пользовательскую модель, в случае отображения пользовательского фрагмента
Но то, что мы можем сделать, это зарегистрировать
onCreate
этого пользователя! = Null, а если нет - вывести его из слоя данных, в противном случае - использовать существующий.Таким образом, мы получаем возможность воссоздания по userId в случае воссоздания фрагментов Android и привязку к действиям пользователя, а также возможность создавать фрагменты, удерживая объект сам или только его идентификатор.
Что-то нравится это:
источник
User user = /*...*/
поместите пользователя в комплект:Bundle bundle = new Bundle(); bundle.putParcelable("some_user", user);
и получите пользователя из аргументов:User user = getArguments().getParcelable("some_user");
объект должен быть реализован интерфейс Parcelable. ссылкаиспользуйте этот код 100% решить вашу проблему
введите этот код в первый фрагмент
этот образец отправляет логические данные
и в SecendFragment
счастливый код
источник
Лучший способ создания экземпляра фрагмента - использовать метод Fragment.instantiate по умолчанию или создать метод фабрики для создания экземпляра фрагмента.
Внимание: всегда создавайте один пустой конструктор во фрагменте, в то время как восстановление памяти фрагмента вызовет исключение во время выполнения.
источник
Я в последнее время здесь. Но кое-что, что я только что знал, могло бы тебе немного помочь.
Если вы используете Java, ничего особенного не изменится. Но для разработчиков kotlin вот следующий фрагмент, который, я думаю, может сделать вас основой для работы:
Удачного кодирования.
источник
setArguments()
бесполезно. Это только приносит беспорядок.источник
onViewCreated
области. Я думаю, это удобно, много способов сделать то же самое. Также это простой способ проверить наличие обновлений, выполненных пользователем (сравнить комплектыgetArguments
и комплектыonSaveInstanceState
)getArguments
вещей. Как насчетonViewCreated
области ... Мы можем восстановить состояние пакета там. Но я просто предпочитаю делатьonCreateView
легкие и быстрые и выполнять всю тяжелую инициализацию внутри,onActivityCreated
потому чтоFragment.getActivity()
иногда хочется вернутьсяnull
и из-заonAttach()
изменений в новой версии API 23.set
иget
Arguments
вsaveInstanceState
. По сути дела, вы делаете то же самое, что и «под капотом»saveInstanceState
"под капотом". И использованиеArguments
- это дублирование функциональности, которое заставляет вас дважды проверять: сначалаArguments
значения, а затемsaveInstanceState
значения. Потому что вы должны использоватьsaveInstanceState
любой способ. Как насчетArguments
... они не нужны.Я считаю, что у меня есть очень простое решение для этого.
источник