Лучшая практика для создания экземпляра нового флекса Android

Я видел две общие практики для создания нового fragmentа в приложении:

Fragment newFragment = new MyFragment(); 

а также

 Fragment newFragment = MyFragment.newInstance(); 

Второй вариант использует статический метод newInstance() и обычно содержит следующий метод.

 public static Fragment newInstance() { MyFragment myFragment = new MyFragment(); return myFragment; } 

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

Я что-то пропустил?

Каковы преимущества одного подхода над другим? Или это просто хорошая практика?

11 Solutions collect form web for “Лучшая практика для создания экземпляра нового флекса Android”

Если Android решает воссоздать fragment позже, он будет вызывать конструктор без аргументов вашего fragmentа. Поэтому перегрузка конструктора не является решением.

С учетом сказанного, способ передать материал вашему fragmentу, чтобы они были доступны после того, как Fragment был воссоздан Android, это передать пакет методу setArguments .

Так, например, если мы хотим передать целое число в fragment, мы будем использовать что-то вроде:

 public static MyFragment newInstance(int someInt) { MyFragment myFragment = new MyFragment(); Bundle args = new Bundle(); args.putInt("someInt", someInt); myFragment.setArguments(args); return myFragment; } 

И позже в Fragment onCreate() вы можете получить доступ к этому целому числу, используя:

 getArguments().getInt("someInt", 0); 

Этот пакет будет доступен, даже если Fragment каким-то образом воссоздается Android.

Также обратите внимание: setArguments можно setArguments только до того, как Фрагмент привязан к Activity.

Этот подход также описан в ссылке разработчика Android: https://developer.android.com/reference/android/app/Fragment.html

Единственное преимущество при использовании newInstance() которое я вижу, следующее:

  1. У вас будет одно место, где все аргументы, используемые fragmentом, могут быть объединены, и вам не нужно писать код ниже каждый раз, когда вы создаете экземпляр fragmentа.

     Bundle args = new Bundle(); args.putInt("someInt", someInt); args.putString("someString", someString); // Put any other arguments myFragment.setArguments(args); 
  2. Его хороший способ рассказать другим classам, какие аргументы он ожидает, чтобы работать верно (хотя вы должны иметь возможность обрабатывать случаи, если в экземпляре fragmentа нет аргументов).

Итак, я считаю, что использование статического newInstance() для создания экземпляра является хорошей практикой.

Есть и другой способ:

 Fragment.instantiate(context, MyFragment.class.getName(), myBundle) 

Хотя @yydl дает вескую причину, почему метод newInstance лучше:

Если Android решает воссоздать fragment позже, он будет вызывать конструктор без аргументов вашего fragmentа. Поэтому перегрузка конструктора не является решением.

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

Прежде чем fragment можно использовать, необходим экземпляр. Android вызывает YourFragment() (конструктор без аргументов ) для создания экземпляра fragmentа. Здесь любой перегруженный конструктор, который вы пишете, будет проигнорирован, так как Android не может знать, какой из них использовать.

В течение жизни Activity fragment создается, как указано выше, и неоднократно уничтожается Android. Это означает, что если вы поместите данные в сам объект fragmentа, он будет потерян после уничтожения fragmentа.

Чтобы обходной путь, андроид просит, чтобы вы хранили данные с помощью Bundle (вызов setArguments() ), к которому затем можно получить доступ из YourFragment . Набор аргументов s защищен Android, и, следовательно, гарантируется постоянство .

Один из способов установить этот пакет – использовать статический метод newInstance :

 public static YourFragment newInstance (int data) { YourFragment yf = new YourFragment() /* See this code gets executed immediately on your object construction */ Bundle args = new Bundle(); args.putInt("data", data); yf.setArguments(args); return yf; } 

Однако конструктор:

 public YourFragment(int data) { Bundle args = new Bundle(); args.putInt("data", data); setArguments(args); } 

может сделать то же самое, что и метод newInstance .

Естественно, это не удастся, и это одна из причин, по которой Android хочет, чтобы вы использовали метод newInstance :

 public YourFragment(int data) { this.data = data; // Don't do this } 

В качестве дополнительного объяснения, вот fragmentарный class Android:

 /** * Supply the construction arguments for this fragment. This can only * be called before the fragment has been attached to its activity; that * is, you should call it immediately after constructing the fragment. The * arguments supplied here will be retained across fragment destroy and * creation. */ public void setArguments(Bundle args) { if (mIndex >= 0) { throw new IllegalStateException("Fragment already active"); } mArguments = args; } 

Обратите внимание, что Android просит установить аргументы только при построении и гарантирует, что они будут сохранены.

EDIT : Как указано в комментариях @JHH, если вы предоставляете настраиваемый конструктор, который требует некоторых аргументов, то Java не предоставит вашему fragmentу конструктор default arg . Таким образом, это потребует от вас определить конструктор no arg , который является кодом, который можно избежать с помощью метода фабрики newInstance .

EDIT : Android не позволяет больше использовать перегруженный конструктор для fragmentов. Вы должны использовать метод newInstance .

Я не согласен с ответом yydi, говоря:

Если Android решает воссоздать fragment позже, он будет вызывать конструктор без аргументов вашего fragmentа. Поэтому перегрузка конструктора не является решением.

Я думаю, что это решение и хорошее, это именно та причина, по которой он был разработан основным языком Java.

Это правда, что система Android может уничтожить и воссоздать ваш Fragment . Таким образом, вы можете сделать это:

 public MyFragment() { // An empty constructor for Android System to use, otherwise exception may occur. } public MyFragment(int someInt) { Bundle args = new Bundle(); args.putInt("someInt", someInt); setArguments(args); } 

Это позволит вам вытащить someInt из getArguments() последним, даже если Fragment был воссоздан системой. Это более элегантное решение, чем static конструктор.

По моему мнению, static конструкторы бесполезны и не должны использоваться. Также они ограничивают вас, если в будущем вы захотите расширить этот Fragment и добавить больше функциональности в конструктор. Со static конструктором вы не можете этого сделать.

Обновить:

Android добавил проверку, что флаг всех нестандартных конструкторов с ошибкой.
Я рекомендую отключить его по указанным выше причинам.

Некоторый код kotlin :

 companion object { fun newInstance(first: String, second: String) : SampleFragment { return SampleFragment().apply { arguments = Bundle().apply { putString("firstString", first) putString("secondString", second) } } } } 

И вы можете получить аргументы:

 val first: String by lazy { arguments?.getString("firstString") ?: "default"} val second: String by lazy { arguments?.getString("secondString") ?: "default"} 

Лучшая практика для fragmentов экземпляра с аргументами в android заключается в том, чтобы в вашем fragmentе был установлен статический заводский метод.

 public static MyFragment newInstance(String name, int age) { Bundle bundle = new Bundle(); bundle.putString("name", name); bundle.putInt("age", age); MyFragment fragment = new MyFragment(); fragment.setArguments(bundle); return fragment; } 

Вам следует избегать установки полей с экземпляром fragmentа. Потому что всякий раз, когда система Android воссоздает ваш fragment, если он чувствует, что системе требуется больше памяти, чем она воссоздает ваш fragment, используя конструктор без аргументов.

Вы можете найти больше информации о лучшей практике для создания fragmentов с аргументами здесь.

Поскольку вопросы о лучшей практике, я бы добавил, что очень часто рекомендуется использовать гибридный подход для создания fragmentа при работе с некоторыми веб-службами REST

Мы не можем передавать сложные объекты, например некоторую модель пользователя, для случая отображения fragmentа пользователя

Но то, что мы можем сделать, – это проверить onCreate user! = onCreate , а если нет – затем привести его с уровня данных, в противном случае – использовать существующий.

Таким образом, мы получаем как способность воссоздать userId в случае восстановления fragmentов Android, так и привязанность к действиям пользователя, а также возможность создавать fragmentы, удерживая объект сам или только его идентификатор

Что-то нравится:

 public class UserFragment extends Fragment { public final static String USER_ID="user_id"; private User user; private long userId; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); if(user==null){ // // Recreating here user from user id(ie requesting from your data model, // which could be services, direct request to rest, or data layer sitting // on application model // user = bringUser(); } } public static UserFragment newInstance(User user, long user_id){ UserFragment userFragment = new UserFragment(); Bundle args = new Bundle(); args.putLong(USER_ID,user_id); if(user!=null){ userFragment.user=user; } userFragment.setArguments(args); return userFragment; } public static UserFragment newInstance(long user_id){ return newInstance(null,user_id); } public static UserFragment newInstance(User user){ return newInstance(user,user.id); } } 

Лучший способ создать экземпляр fragmentа – использовать метод Fragment.instantiate по умолчанию или создать фабричный метод для создания экземпляра fragmentа
Осторожно: всегда создавайте один пустой конструктор в другом fragmentе, в то время как восстановление памяти fragmentа будет вызывать исключение во время выполнения.

setArguments() бесполезен. Это только приносит беспорядок.

 public class MyFragment extends Fragment { public String mTitle; public String mInitialTitle; public static MyFragment newInstance(String param1) { MyFragment f = new MyFragment(); f.mInitialTitle = param1; f.mTitle = param1; return f; } @Override public void onSaveInstanceState(Bundle state) { state.putString("mInitialTitle", mInitialTitle); state.putString("mTitle", mTitle); super.onSaveInstanceState(state); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { if (state != null) { mInitialTitle = state.getString("mInitialTitle"); mTitle = state.getString("mTitle"); } ... } } 

Я считаю, что для этого у меня есть очень простое решение.

 public class MyFragment extends Fragment{ private String mTitle; private List mObjects; public static MyFragment newInstance(String title, List objects) MyFragment myFrag = new MyFragment(); myFrag.mTitle = title; myFrag.mObjects = objects; return myFrag; } 
  • Обратное проектирование из файла APK в проект
  • Как добавить кнопку динамически в Android?
  • Клиент Android REST, образец?
  • Можно ли динамически загружать библиотеку во время выполнения из приложения Android?
  • Android AlarmManager после перезагрузки
  • Пример Android AudioRecord
  • Какая конфигурация ProGuard мне нужна для Firebase на Android?
  • Иконка «Нет приложений» на ActionBar
  • Android, ListView IllegalStateException: «Содержимое адаптера изменилось, но ListView не получил уведомление»
  • Gradle - Что такое ненулевое значение выхода и как его исправить?
  • Как подключить внешний IP-адрес от Java Android
  • Interesting Posts

    ASP.NET MVC 3 – Partial vs Display Template vs Editor Template

    Использование powershell вызывает собственное приложение командной строки и запись STDERR

    Переменная количество аргументов в C ++?

    OpenOffice «строка» для звездочек … как удалить! # $ Вещь?

    Удаленный рабочий стол не будет максимизировать

    Какую команду FFmpeg я использую для перехода через FLV в MP4?

    Как программно установить атрибут стиля в представлении

    Звездочка: вперед, если сверстник недоступен

    Каков наилучший способ клонирования / глубокой копии .NET generic Dictionary ?

    Mysql, как исправить Доступ запрещен для пользователя 'root' @ 'localhost'

    Как я могу взять вывод сценария оболочки и поместить его в файл в командной строке?

    Подключите внешний USB-накопитель в однопользовательском режиме

    Как узнать, работает ли и работает ли служба удаленного рабочего стола?

    Как я могу отображать использование памяти для каждого процесса, если я делаю «ps -ef»?

    Бит-поля в C #

    Давайте будем гением компьютера.