共用方式為


ListView 效能

撰寫行動應用程式時,效能很重要。 使用者期待順暢的捲動和快速載入時間。 無法符合使用者的期望,將花費您在應用程式市集中的評等,或在企業營運應用程式中花費您的組織時間和金錢。

Xamarin.FormsListView是顯示數據的強大檢視,但它有一些限制。 使用自定義數據格時,捲動效能可能會受到影響,特別是當它們包含深層巢狀檢視階層,或使用需要複雜測量的特定版面配置時。 幸運的是,有一些技術可用來避免效能不佳。

快取策略

ListView 通常用來顯示比螢幕上適合的數據多得多。 例如,音樂應用程式可能有具有數千個專案的歌曲連結庫。 為每個專案建立專案會浪費寶貴的記憶體並執行不佳。 不斷建立和終結數據列會要求應用程式持續具現化和清除物件,這也會效能不佳。

為了節省記憶體,每個平臺的原生 ListView 對等專案都有重複使用數據列的內建功能。 只有畫面上可見的儲存格會載入記憶體中, 而內容 會載入現有的儲存格。 此模式可防止應用程式具現化數千個物件,以節省時間和記憶體。

Xamarin.FormsListView允許透過 ListViewCachingStrategy 列舉重複使用儲存格,其具有下列值:

public enum ListViewCachingStrategy
{
    RetainElement,   // the default value
    RecycleElement,
    RecycleElementAndDataTemplate
}

注意

通用 Windows 平台 (UWP) 會RetainElement忽略快取策略,因為它一律會使用快取來改善效能。 因此,根據預設,其行為就像 RecycleElement 套用快取策略一樣。

RetainElement

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

使用 DataTemplateSelector 的 RecycleElement

ListView當 使用 DataTemplateSelector 來選取 DataTemplate時,快RecycleElement取策略不會快取 DataTemplates。 相反地, DataTemplate 會針對清單中的每個資料項目選取 。

注意

RecycleElement取策略有 2.4 中Xamarin.Forms引進的先決條件,當 被要求選取DataTemplate必須傳DataTemplate回相同ViewCell類型的 時DataTemplateSelector。 例如,假設 有 ListViewDataTemplateSelector 可以傳回 的 ,其中MyDataTemplateAViewCell會傳回 MyDataTemplateA 型別的 MyViewCellA,或 MyDataTemplateB (其中 MyDataTemplateB 傳回 ViewCell 型別的 MyViewCellB),則傳回時MyDataTemplateA必須傳回 ,否則會擲回MyViewCellA例外狀況。

RecycleElementAndDataTemplate

RecycleElementAndDataTemplate 取策略會 RecycleElement 以快取策略為基礎,藉由另外確保 ListView 使用 DataTemplateSelector 來選取 DataTemplate時, DataTemplate會由清單中的項目類型快取 。 因此, DataTemplate會為每個項目類型選取一次 ,而不是每個項目實例一次。

注意

RecycleElementAndDataTemplate取策略具有 必要條件,DataTemplate由傳DataTemplateSelector回的 必須使用採用 TypeDataTemplate建構函式。

設定快取策略

列舉 ListViewCachingStrategy 值是以建 ListView 構函式多載來指定,如下列程式代碼範例所示:

var listView = new ListView(ListViewCachingStrategy.RecycleElement);

在 XAML 中 CachingStrategy ,設定 屬性,如下所示:

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

此方法的效果與在 C# 中的建構函式中設定快取策略自變數相同。

在子類別化 ListView 中設定快取策略

CachingStrategy在子類別ListView化上設定 XAML 的屬性不會產生所需的行為,因為上ListView沒有 CachingStrategy 屬性。 此外,如果 已啟用 XAMLC ,會產生下列錯誤訊息: 找不到 『CachingStrategy』 的屬性、可系結屬性或事件

此問題的解決方案是在接受 ListViewCachingStrategy 參數並將它傳遞至基類的子類別ListView上指定建構函式:

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 一標籤,而不是多個標籤。
  • ListViewTableView在顯示非同質數據時,將 取代為 ,也就是不同類型的數據。
  • 限制方法的使用 Cell.ForceUpdateSize 。 如果過度使用,則會降低效能。
  • 在Android上,避免在具現化數據列分隔符的可見性或色彩之後設定 ListView,因為這會導致效能大幅降低。
  • 請避免根據 BindingContext變更儲存格配置。 變更版面配置會產生較大的測量和初始化成本。
  • 避免深度巢狀配置階層。 使用 AbsoluteLayoutGrid 來協助減少巢狀結構。
  • 避免非特定 LayoutOptionsFillFill 是計算成本最低的)。
  • 基於下列原因,請避免將 放在 ListViewScrollView
    • ListView 實作自己的捲動。
    • ListView不會收到任何手勢,因為它們將由父ScrollView代 處理。
    • ListView可以呈現隨清單元素捲動的自定義頁首和頁尾,可能會提供 所使用的功能ScrollView。 如需詳細資訊,請參閱 頁首和頁尾
  • 如果您需要儲存格中呈現的特定複雜設計,請考慮自定義轉譯器。

AbsoluteLayout 有可能在沒有單一量值呼叫的情況下執行版面配置,使其具有高效能。 如果 AbsoluteLayout 無法使用,請考慮 RelativeLayoutRelativeLayout如果使用 ,直接傳遞條件約束的速度會比使用表達式 API 快得多。 這個方法較快,因為表達式 API 會使用 JIT,而且在 iOS 上必須解譯樹狀結構,這較慢。 表達式 API 適用於只有在初始版面配置和旋轉時才需要的頁面版面配置,但在 中 ListView,其會在捲動期間持續執行,因而損害效能。

ListView 或其儲存格建置自定義轉譯器是減少版面配置計算對卷動效能的影響的一種方法。 如需詳細資訊,請參閱 自定義 ListView自定義 ViewCell