2018/2/22

Xamarin.Fomrs 效能提升大全


程式慢,只有兩個原因,一個我們寫不好,一個 Xamarin 沒寫好...

而在寫 Xamarin.Forms 時,其實有很多的眉角,可以提升我們App的效能!!

提升效能的同時,當然也能增加使用者體驗。


效能跟許多東西有關連,最最基本的 C# 程式要顧好,

其他關於 Xamrin.Fomrs 的部分,將會在本篇教學會一一提出 ~

開啟 XAML Compiler

XAML 可以在程式內指定使用 XAML Compiler (XAMLC),它可以將 XAML 轉成中介語言 (IL) 來提升效能,

使用 XAMLC 有以下好處:
  • 編譯期間會檢查 XAML 是否有錯誤
  • 降低讀取 XAML 元件的時間
  • 減少最後產出的檔案大小

Namespace 加入 XAMLC:
using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
  ...
}

Class 加入 XAMLC:
using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
  ...
}

正確的使用 Layout

一個 Layout 可以包含許多的子物件,但如果畫面上只有一個物件,那就不需要用 Layout 了吧!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <ContentPage.Content>
        <StackLayout>
            <Image Source="waterfront.jpg" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
像樓上這樣放就很浪費資源和記憶體,只有一個物件就不需要 Layout了!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <ContentPage.Content>
        <Image Source="waterfront.jpg" />
    </ContentPage.Content>
</ContentPage>

另外,底下範例利用多個 StackLayout 組出的畫面,也是相當浪費效能的
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Details.HomePage"
             Padding="0,20,0,0">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout Orientation="Horizontal">
                <Label Text="Name:" />
                <Entry Placeholder="Enter your name" />
            </StackLayout>
            <StackLayout Orientation="Horizontal">
                <Label Text="Age:" />
                <Entry Placeholder="Enter your age" />
            </StackLayout>
            <StackLayout Orientation="Horizontal">
                <Label Text="Occupation:" />
                <Entry Placeholder="Enter your occupation" />
            </StackLayout>
            <StackLayout Orientation="Horizontal">
                <Label Text="Address:" />
                <Entry Placeholder="Enter your address" />
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

上面的範例可以選擇用 Grid
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Details.HomePage"
             Padding="0,20,0,0">
    <ContentPage.Content>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
            </Grid.RowDefinitions>
            <Label Text="Name:" />
            <Entry Grid.Column="1" Placeholder="Enter your name" />
            <Label Grid.Row="1" Text="Age:" />
            <Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
            <Label Grid.Row="2" Text="Occupation:" />
            <Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
            <Label Grid.Row="3" Text="Address:" />
            <Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
        </Grid>
    </ContentPage.Content>
</ContentPage>

開啟 Layout Compression

慎用,Layout Compression 不適用於外觀屬性、互動屬性(例如 BackgrounColor, IsVisible, Rotation, Scale, TranslationX or TranslationY) 要做設定的物件,壓縮過後會造成物件的屬性失效
Layout Compression 主要是針對 Xamarin.Forms 轉回 Native Language 時,做一個扁平化的動作,會將一些不必要的 "層" 去除。

XAML 開啟 LayoutCompression:
<StackLayout CompressedLayout.IsHeadless="true">
    <StackLayout CompressedLayout.IsHeadless="true" ...>
        <AbsoluteLayout CompressedLayout.IsHeadless="true" ...>
            ...
        </AbsoluteLayout>
    </StackLayout>
    ...
</StackLayout>

也可以在 C# 內開啟:
CompressedLayout.SetIsHeadless(stackLayout, true);

使用 Fast Renderers

在 Android 專案內的 MainActivity.cs,Forms.Init 之前加入這行
Forms.SetFlags("FastRenderers_Experimental");
官方說,Xamarin.fomrs 2.4 版本會針對以下物件做效能的優化
  • Button
  • Image
  • Label
尤其在 ListView 會有顯著的效能提升,若 ListView 有上千筆資料,有可能讓效能提升兩倍以上,資料捲動時更順暢。

減少不必要的 Binding

如果只是簡單的要設定 Button.Text = "Hello" 時,就不要假會還用 ViewModel 去做屬性值 Binding !

相關 Binding 的教學可以從這篇開始看到 MVVM。

Layout 的效能調教

使用 Layout 時有一些細節
  • 減少 Layout 的層數,盡量用 Margin 去安排物件的位置。
  • 使用 Grid 時,請盡量少用 "Auto" size (Row 和 Column 可以設定成 Auto,依照 Cell 內物件的大小計算其寬高)。
  • 除非必要,盡量少用 VerticalOptions HorizontalOptions,設定這兩個值會增加額外的運算。
  • 避免使用 RelativeLayout
  • 使用 AbsoluteLayout 時,避免使用 AbsoluteLayout.AutoSize
  • 使用 StackLayout 時,確定只有一個子物件設定為 LayoutOtpions.Expand,同時設定兩個物件為 Expand 會太浪費效能。
  • 除非必要,不要經常性的更新 "Label",每次的更新都會重新計算 Label 的大小。
  • 除非必要,不要設定 Label.VerticalTextAlignment
  • 請經常將 Label 的 LineBreakMode 設定為 NoWrap
  • AbsoluteLayout 的效能是最好的。


ListView 的效能調教

  • ItemSource 請綁定 IList<T> 類型的資料,不要綁 IEnumerable<T>,IEnumeralble 不支援隨機存取。
  • 盡量使用內建的 cell (像是 TextCell/ SwitchCell),會比 ViewCell 的效能好
  • 越少物件越好,舉例來說,若有多行文字要顯示,可以用一個 Label 搭配 FormattedString,而不是放多個 Label。
  • 如果每一筆的資料型態不一樣,請改用 TableView。
  • 在 Android,不要在 ListView 被實體化後才更改其顏色或是外觀。
  • 除了 LayoutOptions.Fill,其它盡量少用 (Fill 是運算速度最快的)。
  • 不要把 ListView 再放入 ScrollView 內,ListView 本身就有實作 Scroll 的功能。
  • 若你的 Cell 很複雜,建議先做 Custom renderer

減少 Resource Dictinonary 的大小

若有共用的 ResoruceDictionary,就將她放在 Application 內,不要在各頁重複寫
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Resources.App">
     <Application.Resources>
        <ResourceDictionary>
            <Style x:Key="HeadingLabelStyle" TargetType="Label">
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="FontSize" Value="Large" />
                <Setter Property="TextColor" Value="Red" />
            </Style>
        </ResourceDictionary>
     </Application.Resources>
</Application>


相信大家可以讓 Xamarin App 效能更好一點了!!

(下周休刊)



沒有留言:

張貼留言