MyTetra Share
Делитесь знаниями!
ViewPager
21.04.2017
10:48
Раздел: Android - books - AndroidProgramming2e - 11 ViewPager


FragmentStatePagerAdapter и FragmentPagerAdapter

Существует еще один тип PagerAdapter, который можно использовать в приложе

ниях; он называется FragmentPagerAdapter.

FragmentPagerAdapter используется точно так же, как FragmentStatePagerAdapter,

и отличается от него только способом выгрузки неиспользуемых фрагментов

(рис. 11.4).



При использовании класса FragmentStatePagerAdapter неиспользуемый фраг

мент уничтожается. Происходит закрепление транзакции для полного удале

ния фрагмента из объекта FragmentManager активности. Наличие «состояния»


у FragmentStatePagerAdapter определяется тем фактом, что экземпляр при

уничтожении сохраняет объект Bundle вашего фрагмента в методе onSaveIn

stanceState(Bundle). Когда пользователь возвращается обратно, новый фрагмент

восстанавливается по состоянию этого экземпляра.

С другой стороны, FragmentPagerAdapter ничего подобного не делает. Когда фраг

мент становится ненужным, FragmentPagerAdapter вызывает для транзакции

detach(Fragment) вместо remove(Fragment). Представление фрагмента при этом

уничтожается, но экземпляр фрагмента продолжает существовать в FragmentMa

nager. Таким образом, фрагменты, созданные FragmentPagerAdapter, никогда не

уничтожаются (рис. 11.5).


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

StatePagerAdapter более экономно расходует память. Приложение CriminalIntent

выводит список, который со временем может стать достаточно длинным, причем

к каждому элементу списка может прилагаться фотография. Хранить всю эту ин

формацию в памяти нежелательно, поэтому мы используем FragmentStatePager

Adapter.

С другой стороны, если интерфейс содержит небольшое фиксированное коли

чество фрагментов, использование FragmentPagerAdapter безопасно и уместно.

Самый характерный пример такого рода — интерфейс со вкладками. Некоторые

детализированные представления не помещаются на одном экране, поэтому ото

бражаемая информация распределяется между несколькими вкладками. Добавле

ние ViewPager с перебором вкладок делает этот интерфейс интуитивным. Хране

ние фрагментов в памяти упрощает управление кодом контроллера, а поскольку

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

ность, проблемы с нехваткой памяти крайне маловероятны.


Для любознательных: как работает ViewPager

Классы ViewPager и PagerAdapter незаметно выполняют большую часть рутинной

работы. В этом разделе приведена более подробная информация о том, что при

этом происходит.

Прежде чем мы перейдем к обсуждению, предупреждаем: в большинстве случаев

понимать все технические подробности не обязательно.

Но если вы захотите реализовать интерфейс PagerAdapter самостоятельно, вы

должны знать, чем отношения ViewPager-PagerAdapter отличаются от обычных

отношений RecyclerView-Adapter.

Когда может возникнуть необходимость в самостоятельной реализации

интерфейса PagerAdapter? Когда в ViewPager должны размещаться не фрагменты, а нечто иное. Например,

если вы захотите разместить в ViewPager обычные представления View, скажем графические поля,

вы реализуете интерфейс PagerAdapter.

Почему ViewPager, а не RecyclerView?

Использование RecyclerView в данном случае потребует большого объема работы,

потому что вы не сможете использовать существующие экземпляры Fragment.

Adapter ожидает, что вы сможете предоставить View мгновенно. Но когда будет

создано представление вашего фрагмента, решает FragmentManager, а не вы. Таким

образом, когда RecyclerView обратится к Adapter за представлением вашего

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

Именно по этой причине и существует класс ViewPager. Вместо Adapter он использует

класс с именем PagerAdapter. Этот класс сложнее Adapter, потому что он

выполняет больший объем работы по управлению представлениями. Ниже кратко

перечислены основные различия. Вместо метода onBindViewHolder(…), возвращающего ViewHolder с соответствующим

представлением, PagerAdapter содержит следующие методы:

public Object instantiateItem(ViewGroup container, int position)

public void destroyItem(ViewGroup container, int position, Object object)

public abstract boolean isViewFromObject(View view, Object object)

Метод pagerAdapter.instantiateItem(ViewGroup, int) приказывает адаптеру создать представление

элемента списка для заданной позиции и добавить его в контейнер ViewGroup;

метод destroyItem(ViewGroup, int, Object) приказывает уничтожить этот элемент.

Обратите внимание: метод instantiateItem(ViewGroup, int)

не приказывает создать представление немедленно. PagerAdapter может создать

представление в любой момент в будущем. После того как представление было создано,

ViewPager в какой-то момент замечает его. Чтобы понять, к какому элементу списка оно относится, ViewPager вы-

зывает метод isViewFromObject(View, Object). Параметр Object содержит объект,

полученный при вызове instantiateItem(ViewGroup, int). Таким образом, если

ViewPager вызывает instantiateItem(ViewGroup, 5) и получает объект A, вызов

isViewFromObject(View, A) должен вернуть true, если переданный экземпляр View

относится к элементу 5, и false в противном случае.

Этот процесс достаточно сложен для ViewPager, но не для класса PagerAdapter,

который должен уметь только создавать представления, уничтожать представ

ления и определять, к какому объекту относится представление. Менее жесткие

требования позволяют реализации PagerAdapter создавать и добавлять новый

фрагмент в instantiateItem(ViewGroup, int) и возвращать фрагмент как отсле

живаемый экземпляр Object. При этом isViewFromObject(View, Object) выглядит

примерно так:

@Override

public boolean isViewFromObject(View view, Object object) {

return ((Fragment)object).getView() == view;

}

Реализовывать переопределения PagerAdapter каждый раз, когда потребуется

использовать ViewPager, было бы слишком утомительно. Хорошо, что у нас есть

FragmentPagerAdapter и FragmentStatePagerAdapter.


Для любознательных: формирование макетов представлений в коде

В этой книге макеты представлений определяются исключительно в XML-файлах

макетов. Также возможно создавать макеты представлений в коде.

Собственно, ViewPager можно было бы определить полностью в коде вообще без

файла макета:

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ViewPager viewPager = new ViewPager(this);

setContentView(viewPager);

...

}

Создание представления не требует никакого волшебства; просто вызовите его

конструктор и передайте параметр Context. Всю иерархию представлений можно

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

Тем не менее строить представления в коде не рекомендуется, потому что файлы

макетов предоставляют ряд преимуществ.

Первое преимущество файлов макетов заключается в том, что они обеспечивают

четкое разделение между контроллером и объектами представлений в приложе

нии. Представление существует в XML, контроллер существует в коде Java. Это

разделение упрощает сопровождение кода за счет ограничения объема изменений

в контроллере при изменении представления, и наоборот.

Другое преимущество определения представлений в XML заключается в том, что

система уточнения ресурсов Android позволяет автоматически выбрать версию

файла XML в зависимости от свойств устройства.

Как было показано в главе 3, эта система позволяет легко сменить файл макета

в зависимости от ориентации устройства (а также других параметров конфигура

ции).

Есть ли у файлов макетов какие-либо недостатки? Пожалуй, хлопоты с созданием

файла XML и его заполнением. Если вы создаете всего одно представление, ино

гда эти хлопоты могут показаться излишними.

В остальном сколько-нибудь серьезных недостатков нет — группа разработки

Android никогда не рекомендовала строить иерархии представлений на про

граммном уровне, даже в прежние времена, когда разработчикам приходилось

беспокоиться о быстродействии больше, чем сейчас. Даже если вам требуется

нечто настолько мелкое, как представление с идентификатором (что часто тре

буется для представлений, созданных на программном уровне), проще создать

файл макета.

 
MyTetra Share v.0.52
Яндекс индекс цитирования