Android studio fragment newinstance

Фрагменты

Существует два основных подхода в использовании фрагментов.

Первый способ основан на замещении родительского контейнера. Создаётся стандартная разметка и в том месте, где будут использоваться фрагменты, размещается контейнер, например, FrameLayout. В коде контейнер замещается фрагментом. При использовании подобного сценария в разметке не используется тег fragment, так как его нельзя менять динамически. Также вам придётся обновлять ActionBar, если он зависит от фрагмента. Здесь показан такой пример.

Второй вариант — используются отдельные разметки для телефонов и планшетов, которые можно разместить в разных папках ресурсов. Например, если в планшете используется двухпанельная разметка с двумя фрагментами на одной активности, мы используем эту же активность для телефона, но подключаем другую разметку, которая содержит один фрагмент. Когда нам нужно переключиться на второй фрагмент, то запускаем вторую активность.

Второй подход является наиболее гибким и в целом предпочтительным способом использования фрагментов. Активность проверяет в каком режиме (свои размеры) он запущен и использует разную разметку из ресурсов. Графически это выглядит следующим образом.

Основные классы

Сами фрагменты наследуются от androidx.fragment.app.Fragment. Существует подклассы фрагментов: ListFragment, DialogFragment, PreferenceFragment, WebViewFragment и др. Не исключено, что число классов будет увеличиваться, например, появился ещё один класс MapFragment.

Для взаимодействия между фрагментами используется класс android.app.FragmentManager — специальный менеджер по фрагментам.

Как в любом офисе, спецманагер не делает работу своими руками, а использует помощников. Например, для транзакций (добавление, удаление, замена) используется класс-помощник android.app.FragmentTransaction.

Для сравнения приведу названия классов из библиотеки совместимости:

  • android.support.v4.app.FragmentActivity
  • android.support.v4.app.Fragment
  • android.support.v4.app.FragmentManager
  • android.support.v4.app.FragmentTransaction

Как видите, разница в одном классе, который я привёл первым. Он используется вместо стандартного Activity, чтобы система поняла, что придётся работать с фрагментами. На данный момент студия создаёт проект на основе ActionBarActivity, который является подклассом FragmentActivity.

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

В 2018 году Гугл объявила фрагменты из пакета androd.app устаревшими. Заменяйте везде на версию из библиотеки совместимости. В 2020 году уже используют пакет androidx.fragment.app.

В версии Support Library 27.1.0 появились новые методы requireActivity() и requireContext(), которые пригодятся при написании кода, когда требуется наличие активности и нужно избежать ошибки на null.

Общий алгоритм работы с фрагментами будет следующим:

У каждого фрагмента должен быть свой класс. Класс наследуется от класса Fragment или схожих классов, о которых говорилось выше. Это похоже на создание новой активности или нового компонента.

Также, как в активности, вы создаёте различные методы типа onCreate() и т.д. Если фрагмент имеет разметку, то используется метод onCreateView() — считайте его аналогом метода setContentView(), в котором вы подключали разметку активности. При этом метод onCreateView() возвращает объект View, который является корневым элементом разметки фрагмента.

Разметку для фрагмента можно создать программно или декларативно через XML.

Создание разметки для фрагмента ничем не отличается от создания разметки для активности. Вот отрывок кода из метода onCreateView():

Глядя на этот код, вы должные понять, что фрагмент использует разметку из файла res/layout/first_fragment.xml, которая содержит кнопку с идентификатором android:id=»@+id/button_first». Здесь также прослеживается сходство с подключением компонентов в активности. Обратите внимание, что перед методом findViewById() используется view, так как этот метод относится к компоненту, а не к активности, как мы обычно делали в программах, когда просто опускали имя активности. Т.е. в нашем случае мы ищем ссылку на кнопку не среди разметки активности, а внутри разметки самого фрагмента.

Нужно помнить, что в методе inflate() последний параметр должен иметь значение false в большинстве случаев.

FragmentManager

Класс FragmentManager имеет два метода, позволяющих найти фрагмент, который связан с активностью:

findFragmentById(int id) Находит фрагмент по идентификатору findFragmentByTag(String tag) Находит фрагмент по заданному тегу

Методы транзакции

Мы уже использовали некоторые методы класса FragmentTransaction. Познакомимся с ними поближе

Читайте также:  Не грузятся страницы андроид

add() Добавляет фрагмент к активности remove() Удаляет фрагмент из активности replace() Заменяет один фрагмент на другой hide() Прячет фрагмент (делает невидимым на экране) show() Выводит скрытый фрагмент на экран detach() (API 13) Отсоединяет фрагмент от графического интерфейса, но экземпляр класса сохраняется attach() (API 13) Присоединяет фрагмент, который был отсоединён методом detach()

Методы remove(), replace(), detach(), attach() не применимы к статичным фрагментам.

Перед началом транзакции нужно получить экземпляр FragmentTransaction через метод FragmentManager.beginTransaction(). Далее вызываются различные методы для управления фрагментами.

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

Аргументы фрагмента

Фрагменты должны сохранять свою модульность и не должны общаться друг с другом напрямую. Если один фрагмент хочет докопаться до другого, он должен сообщить об этом своему менеджеру активности, а он уже передаст просьбу другому фрагменту. И наоборот. Это сделано специально для того, чтобы было понятно, что менеджер тут главный и он не зря зарплату получает. Есть три основных способа общения фрагмента с активностью.

  • Активность может создать фрагмент и установить аргументы для него
  • Активность может вызвать методы экземпляра фрагмента
  • Фрагмент может реализовать интерфейс, который будет использован в активности в виде слушателя

Фрагмент должен иметь только один пустой конструктор без аргументов. Но можно создать статический newInstance с аргументами через метод setArguments().

Доступ к аргументам можно получить в методе onCreate() фрагмента:

Динамически загружаем фрагмент в активность.

Если активность должна выполнить какую-то операцию в фрагменте, то самый простой способ — задать нужный метод в фрагменте и вызвать данный метод через экземпляр фрагмента.

Вызываем метод в активности:

Если фрагмент должен сообщить о своих действиях активности, то следует реализовать интерфейс.

Управление стеком фрагментов

Фрагменты, как и активности, могут управляться кнопкой Back. Вы можете добавить несколько фрагментов, а потом через кнопку Back вернуться к первому фрагменту. Если в стеке не останется ни одного фрагмента, то следующее нажатие кнопки закроет активность.

Чтобы добавить транзакцию в стек, вызовите метод FragmentTransaction.addToBackStack(String) перед завершением транзакции (commit). Строковый аргумент — опциональное имя для идентификации стека или null. Класс FragmentManager имеет метод popBackStack(), возвращающий предыдущее состояние стека по этому имени.

Если вы вызовете метод addToBackStack() при удалении или замещении фрагмента, то будут вызваны методы фрагмента onPause(), onStop(), onDestroyView().

Когда пользователь нажимает на кнопку возврата, то вызываются методы фрагмента onCreateView(), onActivityCreated(), onStart() и onResume().

Рассмотрим пример реагирования на кнопку Back в фрагменте без использования стека. Активность имеет метод onBackPressed(), который реагирует на нажатие кнопки. Мы можем в этом методе сослаться на нужный фрагмент и вызвать метод фрагмента.

Теперь в классе фрагмента прописываем метод с нужным кодом.

Более желательным вариантом является использование интерфейсов. В некоторых примерах с фрагментами такой приём используется.

Интеграция Action Bar/Options Menu

Фрагменты могут добавлять свои элементы в панель действий или меню активности. Сначала вы должны вызвать метод Fragment.setHasOptionsMenu() в методе фрагмента onCreate(). Затем нужно задать настройки для методов фрагмента onCreateOptionsMenu() и onOptionsItemSelected(), а также при необходимости для методов onPrepareOptionsMenu(), onOptionsMenuClosed(), onDestroyOptionsMenu(). Работа методов фрагмента ничем не отличается от аналогичных методов для активности.

В активности, которая содержит фрагмент, данные методы автоматически сработают.

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

Код для активности:

Код для фрагмента:

Связь между фрагментом и активностью

Экземпляр фрагмента связан с активностью. Активность может вызывать методы фрагмента через ссылку на объект фрагмента. Доступ к фрагменту можно получить через методы findFragmentById() или findFragmentByTag().

Источник

Понимание метода Fragment.newInstance

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

Я не понимаю, кто звонит newInstance . Мое первое впечатление заключалось в том, что, поскольку для этого метода newInstance можно определить произвольные аргументы, я должен добавить его явный вызов где-нибудь в приложении, а имя newInstance — это просто соглашение об именах. Но тогда я бы создал второй фрагмент в дополнение к фрагменту, созданному фреймворком, вызывающим конструктор по умолчанию, что меня смущает.

Читайте также:  Ios для андроид apk

Так является ли вышеприведенное предположение неверным, и действительно ли метод newInstance каким-то образом является перегрузкой встроенного метода Java для создания экземпляра класса? В этом случае я не понимаю, как я могу определить метод newinstance , который принимает произвольный список аргументов. Или это возможно в Java, а я просто недостаточно хорошо знаю Java?

3 ответа

Вы можете назвать функцию как хотите: newInstance , getInstance , newFragment . Неважно, это всего лишь вспомогательный метод. Важно то, что вы помещаете все свои аргументы в fragment.setArguments(args) . Система Android запомнит эти аргументы и будет использовать их при воссоздании фрагмента.

Fragment.newInstance(args1,args2. ) используется как метод статического построения. О преимуществах статического метода строительства говорить не приходится. Но в Fragment это может помочь нам сохранить аргументы, и мы можем получить эти аргументы в методе onCreate() , когда случайно ваше приложение бум, а Android поможет вам восстановить ваш фрагмент с помощью Constructor без аргументов.

Не забудьте использовать Parcelable вместо Serializable .

newInstance — это шаблон проектирования Android, поскольку у Fragment не должно быть других Constructor рядом с значением по умолчанию Constructor

Таким образом, вы определяете вспомогательную функцию для передачи аргументов Fragment

Вам не обязательно его использовать, но, допустим, у вас есть 2 Activities , которые оба начинают FragmentA

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

Я не понимаю, кто вызывает newInstance.

Обычно вы будете использовать метод instantiate из мест, которые создают Fragments . Activity , Adapter и тому подобное.

Где PlaceholderFragment.newInstance(int position)

В этом случае я не понимаю, как я могу определить метод newinstance, который принимает произвольный список аргументов.

Вы можете передать произвольный список аргументов, но вам нужно знать значение Type , потому что Bundle имеет только putX() методы, где X — это тип параметра

Источник

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

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

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

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

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

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

ОТВЕТЫ

Ответ 1

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

С учетом сказанного, способ передать материал вашему фрагменту, чтобы они были доступны после воссоздания Фрагмента Android, — передать пакет методу setArguments .

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

Существует и другой способ:

Ответ 4

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

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

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

Читайте также:  Красивые шахматы для андроид

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

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

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

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

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

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

Как дополнительное объяснение, здесь Android Fragment Class:

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

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

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

Ответ 5

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

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

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

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

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

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

Update:

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

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

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

Источник

Оцените статью