Производительность ListView
При написании мобильных приложений производительность имеет значение. Пользователи ожидали плавной прокрутки и быстрой загрузки. Не отвечая ожиданиям пользователей, вы будете стоить оценки в магазине приложений или в случае бизнес-приложения, стоить вашей организации время и деньги.
Это Xamarin.FormsListView
мощное представление для отображения данных, но оно имеет некоторые ограничения. Производительность прокрутки может страдать при использовании пользовательских ячеек, особенно если они содержат иерархии глубоко вложенных представлений или используют определенные макеты, требующие сложного измерения. К счастью, есть методы, которые можно использовать, чтобы избежать плохой производительности.
Стратегия кэширования
ListViews часто используются для отображения гораздо большего количества данных, чем соответствует экрану. Например, у музыкального приложения может быть библиотека песен с тысячами записей. Создание элемента для каждой записи будет тратить ценную память и плохо работать. Постоянно создавая и уничтожая строки, приложение будет постоянно создавать экземпляры и очищать объекты, которые также будут работать плохо.
Для экономии памяти собственные ListView
эквиваленты для каждой платформы имеют встроенные функции для повторного использования строк. Только ячейки, видимые на экране, загружаются в память, а содержимое загружается в существующие ячейки. Этот шаблон не позволяет приложению создавать экземпляры тысяч объектов, сохранять время и память.
Xamarin.FormsListView
разрешает повторное использование ячеек через ListViewCachingStrategy
перечисление, которое имеет следующие значения:
public enum ListViewCachingStrategy
{
RetainElement, // the default value
RecycleElement,
RecycleElementAndDataTemplate
}
Примечание.
Универсальная платформа Windows (UWP) игнорирует RetainElement
стратегию кэширования, так как она всегда использует кэширование для повышения производительности. Поэтому по умолчанию она ведет себя так, как если RecycleElement
бы применяется стратегия кэширования.
СохранитьElement
Стратегия RetainElement
кэширования указывает, что ListView
будет создавать ячейку для каждого элемента в списке и является поведением по умолчанию ListView
. Его следует использовать в следующих обстоятельствах:
- Каждая ячейка имеет большое количество привязок (20–30+).
- Шаблон ячейки часто изменяется.
- Тестирование показывает, что
RecycleElement
стратегия кэширования приводит к снижению скорости выполнения.
Важно распознать последствия RetainElement
стратегии кэширования при работе с пользовательскими ячейками. Любой код инициализации ячеек должен выполняться для каждого создания ячейки, что может быть несколько раз в секунду. В этом случае методы макета, которые были тонкими на странице, как использование нескольких вложенных StackLayout
экземпляров, становятся узкими местами производительности при настройке и уничтожении в режиме реального времени при прокрутке пользователя.
RecycleElement
Стратегия RecycleElement
кэширования указывает, что ListView
попытка свести к минимуму объем памяти и скорость выполнения путем перезапуска ячеек списка. Этот режим не всегда предлагает улучшение производительности и тестирование должно выполняться для определения каких-либо улучшений. Тем не менее, это предпочтительный выбор, и его следует использовать в следующих обстоятельствах:
- Каждая ячейка имеет небольшое или умеренное количество привязок.
- Каждая ячейка
BindingContext
определяет все данные ячейки. - Каждая ячейка в значительной степени аналогична шаблону ячейки.
Во время виртуализации ячейка будет обновлять контекст привязки и поэтому, если приложение использует этот режим, оно должно убедиться, что обновления контекста привязки обрабатываются соответствующим образом. Все данные о ячейке должны поступать из контекста привязки или ошибок согласованности. Эту проблему можно избежать с помощью привязки данных для отображения данных ячейки. Кроме того, данные ячеек должны быть заданы в переопределении, а не в OnBindingContextChanged
конструкторе пользовательской ячейки, как показано в следующем примере кода:
public class CustomCell : ViewCell
{
Image image = null;
public CustomCell ()
{
image = new Image();
View = image;
}
protected override void OnBindingContextChanged ()
{
base.OnBindingContextChanged ();
var item = BindingContext as ImageItem;
if (item != null) {
image.Source = item.ImageUrl;
}
}
}
Дополнительные сведения см. в разделе "Изменения контекста привязки".
В iOS и Android, если ячейки используют пользовательские отрисовщики, они должны убедиться, что уведомление об изменении свойств реализовано правильно. Когда ячейки повторно используются, значения свойств изменяются при обновлении контекста привязки до доступной ячейки, при PropertyChanged
этом возникают события. Дополнительные сведения см. в разделе "Настройка ViewCell".
RecycleElement с dataTemplateSelector
Если используется для DataTemplateSelector
ListView
выбораDataTemplate
, RecycleElement
стратегия кэширования не кэширует DataTemplate
s. Вместо этого выбирается для DataTemplate
каждого элемента данных в списке.
Примечание.
Стратегия RecycleElement
кэширования имеет необходимые требования, представленные в Xamarin.Forms версии 2.4, что при DataTemplateSelector
запросе выбрать DataTemplate
тот же тип, каждый из которых DataTemplate
должен возвращать один и тот же ViewCell
тип. Например, если задано ListView
значение, DataTemplateSelector
которое может возвращать MyDataTemplateA
либо (где MyDataTemplateA
возвращает типMyViewCellA
), либо MyDataTemplateB
(где MyDataTemplateB
возвращает ViewCell
MyViewCellB
ViewCell
тип), когда MyDataTemplateA
возвращается он должен возвращать MyViewCellA
или возникает исключение.
RecycleElementAndDataTemplate
Стратегия RecycleElementAndDataTemplate
кэширования основывается на RecycleElement
стратегии кэширования, дополнительно гарантируя, что при ListView
использовании DataTemplateSelector
выбранного DataTemplate
DataTemplate
элемента кэшируются по типу элемента в списке. Таким образом, DataTemplate
значения s выбираются один раз на тип элемента, а не один раз на экземпляр элемента.
Примечание.
Стратегия RecycleElementAndDataTemplate
кэширования имеет предварительные требования, которые DataTemplate
возвращаются DataTemplateSelector
DataTemplate
конструктором, который принимает Type
.
Настройка стратегии кэширования
Значение ListViewCachingStrategy
перечисления указывается с перегрузкой ListView
конструктора, как показано в следующем примере кода:
var listView = new ListView(ListViewCachingStrategy.RecycleElement);
В XAML задайте CachingStrategy
атрибут, как показано в коде XAML ниже:
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Этот метод имеет тот же эффект, что и установка аргумента стратегии кэширования в конструкторе в C#.
Настройка стратегии кэширования в подклассном ListView
CachingStrategy
Задание атрибута из XAML в подклассе ListView
не приведет к возникновению требуемого поведения, так как в ней нет CachingStrategy
свойстваListView
. Кроме того, если XAMLC включен, будет создано следующее сообщение об ошибке: нет свойства, привязываемого свойства или события для CachingStrategy.
Решение этой проблемы заключается в указании конструктора подкласса ListView
, который принимает ListViewCachingStrategy
параметр и передает его в базовый класс:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
ListViewCachingStrategy
Затем значение перечисления можно указать из XAML с помощью синтаксисаx:Arguments
:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
Предложения по производительности ListView
Существует множество методов повышения производительности ListView
. Следующие предложения могут повысить производительность ListView.
- Привязывайте
ItemsSource
свойство кIList<T>
коллекции вместоIEnumerable<T>
коллекции, так какIEnumerable<T>
коллекции не поддерживают случайный доступ. - Используйте встроенные ячейки (например
TextCell
/SwitchCell
), а не всякийViewCell
раз, когда вы можете. - Используйте меньше элементов. Например, рекомендуется использовать одну
FormattedString
метку вместо нескольких меток. - Замените его
ListView
TableView
на отображение неоднородных данных, то есть данных разных типов. - Ограничение использования
Cell.ForceUpdateSize
метода. Если превышено, это приведет к снижению производительности. - В Android не устанавливайте
ListView
видимость или цвет разделителя строк после создания экземпляра, так как это приводит к большому штрафу за производительность. - Избегайте изменения макета ячейки на
BindingContext
основе . Изменение макета вызывает большие затраты на измерение и инициализацию. - Избегайте глубоко вложенных иерархий макета. Использование
AbsoluteLayout
илиGrid
уменьшение вложения. - Избегайте конкретных,
LayoutOptions
кромеFill
(Fill
является самым дешевым для вычислений). - Избегайте размещения
ListView
внутри поScrollView
следующим причинам:- Реализует
ListView
собственную прокрутку. - Не
ListView
будет получать никаких жестов, так как они будут обрабатываться родительскимScrollView
элементом. - Он
ListView
может представить настраиваемый верхний и нижний колонтитул, который прокручивается с элементами списка, потенциально предлагая функциональные возможности, которыеScrollView
использовались для. Дополнительные сведения см. в разделе "Верхние и нижние колонтитулы".
- Реализует
- Рассмотрите пользовательский отрисовщик, если вам нужен конкретный сложный дизайн, представленный в ячейках.
AbsoluteLayout
имеет потенциал для выполнения макетов без вызова одной меры, что делает его высокопроизводительным. Если AbsoluteLayout
не удается использовать, рассмотрите вопрос RelativeLayout
. При использовании RelativeLayout
передача ограничений напрямую будет значительно быстрее, чем с помощью API выражений. Этот метод быстрее, так как API выражений использует JIT, и в iOS дерево должно быть интерпретировано медленнее. API выражений подходит для макетов страниц, где он требуется только для начального макета и поворота, но в ListView
том месте, где он выполняется постоянно во время прокрутки, он повредит производительность.
Создание пользовательского отрисовщика для ListView
ячейки является одним из способов уменьшения эффекта вычислений макета на производительность прокрутки. Дополнительные сведения см. в разделе "Настройка ListView " и настройка ViewCell.