Zvýšení Xamarin.Forms výkonu aplikace

Vývoj 2016: optimalizace výkonu aplikace pomocí

Nízký výkon aplikace prezentuje mnoho způsobů. Může dojít k tomu, že aplikace přestane reagovat, může způsobit pomalé posouvání a může snížit výdrž baterie zařízení. Optimalizace výkonu však zahrnuje více než pouze implementaci efektivního kódu. Také je nutné vzít v úvahu činnost uživatele při výkonu aplikace. Například zajistěte, aby se operace prováděly bez blokování uživatele, aby mohli provádět další aktivity, což může pomoci zlepšit uživatelské prostředí.

Existuje mnoho postupů pro zvýšení výkonu a zjištěného výkonu Xamarin.Forms aplikací. Souhrnně tyto techniky můžou významně snížit množství práce prováděné CPU a množství paměti, které aplikace spotřebovává.

Poznámka

Než si přečtete tento článek, měli byste nejdřív přečíst výkon pro různé platformy, který popisuje techniky specifické pro jiné platformy, aby se zlepšilo využití paměti a výkon aplikací vytvořených pomocí platformy Xamarin.

Povolit kompilátor XAML

XAML lze volitelně zkompilovat přímo do jazyka IL (Intermediate Language) s kompilátorem XAML (XAMLC). XAMLC nabízí několik výhod:

  • Provádí kontrolu v době kompilace XAML a oznamuje uživateli jakékoli chyby.
  • Odstraní některé doby načítání a vytváření instancí pro prvky jazyka XAML.
  • Pomáhá snižovat velikost souboru finálního sestavení tím, že už nezahrnuje soubory. XAML.

XAMLC je ve výchozím nastavení povolená v nových Xamarin.Forms řešeních. Může být ale nutné povolit ve starších řešeních. Další informace naleznete v tématu kompilace XAML.

Použít zkompilované vazby

Zkompilované vazby zlepšují výkon datových vazeb v Xamarin.Forms aplikacích pomocí řešení výrazů vazby v době kompilace, nikoli za běhu s reflexí. Kompilování výrazu vazby generuje zkompilovaný kód, který obvykle vyhodnocuje vazbu 8-20 krát rychleji než použití klasické vazby. Další informace najdete v tématu zkompilované vazby.

Omezení zbytečných vazeb

Nepoužívejte vazby pro obsah, který lze snadno nastavit staticky. Není k dispozici žádná výhoda ve vazbě dat, která není nutné svázat, protože vazby nejsou nákladově efektivní. Například nastavení Button.Text = "Accept" má méně režijních nákladů než vazba Xamarin_Forms Button.Text = "Accept" _Button_Text "data-LINKTYPE =" absolutní cesta ">Button.Textstring vlastnost ViewModel s hodnotou" Accept ".

Použití rychlých zobrazovacích modulů

Rychlé vykreslovací prvky snižují náklady na inflační a zobrazovací Xamarin.Forms kontrolu v Androidu díky sloučení výsledné hierarchie nativních ovládacích prvků. Tím se zvyšuje výkon tím, že se vytvoří méně objektů, což ve výsledku vede k méně složitému vizuálnímu stromu a k menšímu využití paměti.

Od verze Xamarin.Forms 4,0 a vyšší jsou všechny aplikace zaměřené na FormsAppCompatActivity použití rychlých zobrazovacích aplikací ve výchozím nastavení. Další informace najdete v tématu rychlé zobrazovací jednotky.

Povolit trasování po spuštění v Androidu

Kompilace v čase (AOT) v systému Android minimalizuje náklady na spuštění aplikace za běhu a využití paměti za cenu tvorby mnohem větší APK. Alternativou je použití trasování po spuštění, které poskytuje kompromis mezi velikostí a časem spuštění APK pro Android a ve srovnání s konvenční kompilací AOT.

Namísto kompilování co největší části aplikace do nespravovaného kódu, trasování spouštění zkompiluje pouze sadu spravovaných metod, které reprezentují nejdražších částí spuštění aplikace v prázdné Xamarin.Forms aplikaci. Tento přístup má za následek menší velikost APK ve srovnání s konvenční kompilací AOT a zároveň nabízí podobnou vylepšení při spuštění.

Povolit kompresi rozložení

Komprese rozložení odstraní určená rozložení z vizuálního stromu a pokusí se zlepšit výkon vykreslování stránky. Výhoda výkonu, kterou tato výhoda přináší, se liší v závislosti na složitosti stránky, používané verzi operačního systému a zařízení, na kterém je aplikace spuštěná. Na starších zařízeních se ale zobrazí největší nárůst výkonu. Další informace najdete v tématu Komprese rozložení.

Zvolit správné rozložení

Rozložení, které umožňuje zobrazit více podřízených objektů, ale má pouze jeden podřízený prvek, je wasteful. Například následující příklad kódu ukazuje StackLayout s jedním podřízeným prvkem:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <StackLayout>
        <Image Source="waterfront.jpg" />
    </StackLayout>
</ContentPage>

To je wasteful a StackLayout element by měl být odebrán, jak je znázorněno v následujícím příkladu kódu:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <Image Source="waterfront.jpg" />
</ContentPage>

Kromě toho se nepokuste znovu vytvořit vzhled konkrétního rozložení pomocí kombinací jiných rozložení, protože to vede k nepotřebným výpočtům rozložení. Neprovádějte například pokus o reprodukování Grid rozložení pomocí kombinace StackLayout instancí. Následující příklad kódu ukazuje příklad tohoto chybného postupu:

<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">
    <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>

To je wasteful, protože se neprovádí nepotřebné výpočty rozložení. Místo toho lze lépe dosáhnout požadovaného rozložení pomocí Grid , jak je znázorněno v následujícím příkladu kódu:

<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">
    <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>

Optimalizovat výkon rozložení

Chcete-li získat nejlepší možný výkon rozložení, postupujte podle těchto pokynů:

Použít asynchronní programování

Pomocí asynchronního programování se dá zvýšit celková odezva vaší aplikace a problémová místa výkonu se jim často vyhne. V rozhraní .NET je pro asynchronní operace doporučený vzor návrhu (klepněte na základě úloh) . Nesprávné použití klepnutí ale může mít za následek nevýkonné aplikace. Při použití klepnutí byste proto měli dodržovat následující pokyny.

Základy

  • Pochopení životního cyklu úkolu, který je reprezentován TaskStatus výčtem. Další informace najdete v tématu význam stav úkolu a stav úlohy.

  • Použijte Task.WhenAll metodu pro asynchronní čekání na dokončení více asynchronních operací, nikoli pro jednotlivé await řady asynchronních operací. Další informace najdete v tématu Task. WhenAll.

  • Použijte Task.WhenAny metodu k asynchronnímu čekání na dokončení jedné z několika asynchronních operací. Další informace najdete v tématu Task. WhenAny.

  • Použijte Task.Delay metodu k vytvoření Task objektu, který skončí po určenou dobu. To je užitečné pro scénáře, jako je cyklické dotazování na data, a zpoždění zpracování vstupu uživatele pro předem stanovený čas. Další informace najdete v tématu Task. Delay.

  • Proveďte náročné synchronní operace procesoru ve fondu vláken s Task.Run metodou. Tato metoda je zástupcem pro TaskFactory.StartNew metodu s nejoptimálními argumenty sady. Další informace najdete v tématu Task. Run.

  • Vyhněte se pokusu o vytvoření asynchronních konstruktorů. Místo toho použijte pro správnou inicializaci události životního cyklu nebo samostatnou inicializační logiku await . Další informace najdete v tématu asynchronní konstruktory na blog.stephencleary.com.

  • Použijte model opožděné úlohy, abyste se vyhnuli čekání na dokončení asynchronních operací během spuštění aplikace. Další informace najdete v tématu AsyncLazy.

  • Vytvořte obálku úlohy pro existující asynchronní operace, které nepoužívají klepnutí, vytvořením TaskCompletionSource<T> objektů. Tyto objekty získají výhody Task programovatelnosti a umožňují řídit dobu života a dokončení přidružených Task . Další informace najdete v tématu charakter TaskCompletionSource.

  • Vrátí Task objekt namísto vrácení očekávaného objektu, není- Task li nutné zpracovat výsledek asynchronní operace. To je více prováděno z důvodu méně prováděného přepínání kontextu.

  • Použijte knihovnu toku dat Task Parallel Library (TPL) ve scénářích, jako je například zpracování dat, když jsou k dispozici, nebo pokud máte více operací, které musí vzájemně komunikovat asynchronně. Další informace najdete v tématu tok dat (Task Parallel Library).

Uživatelské rozhraní

  • Zavolejte asynchronní verzi rozhraní API, pokud je k dispozici. Tím se ponechá vlákno uživatelského rozhraní odblokované, což vám pomůže zlepšit činnost uživatele s aplikací.

  • Aktualizujte prvky uživatelského rozhraní daty z asynchronních operací ve vlákně uživatelského rozhraní, aby se předešlo vyjímka výjimek. Aktualizace ListView.ItemsSource vlastnosti však budou automaticky zařazeny do vlákna uživatelského rozhraní. Informace o tom, jak určit, jestli je kód spuštěný ve vlákně UI, najdete v tématu Xamarin.Essentials: MainThread .

    Důležité

    Všechny vlastnosti ovládacích prvků, které jsou aktualizovány prostřednictvím datové vazby, budou automaticky zařazeny do vlákna uživatelského rozhraní.

Zpracování chyb

  • Seznamte se s asynchronním zpracováním výjimek. Neošetřené výjimky, které jsou vyvolány asynchronně spuštěným kódem, jsou šířeny zpět do volajícího vlákna, s výjimkou určitých scénářů. Další informace naleznete v tématu zpracování výjimek (Task Parallel Library).
  • Vyhněte se vytváření async void metod a místo toho vytvořit async Task metody. Tyto možnosti umožňují snazší zpracování chyb, možnosti skládání a testování. Výjimkou z této zásady jsou asynchronní obslužné rutiny událostí, které musí vracet void . Další informace naleznete v tématu zamezení asynchronní void.
  • Nepoužívejte kombinaci blokujícího a asynchronního kódu voláním Task.WaitTask.Result metod, nebo GetAwaiter().GetResult , protože by mohlo dojít k zablokování. Nicméně pokud je nutné tyto zásady porušovat, je upřednostňovaným přístupem volání GetAwaiter().GetResult metody, protože zachovává výjimky úloh. Další informace naleznete v tématu Async All a tasking Exception in .NET 4,5.
  • Použijte ConfigureAwait metodu, kdykoli je to možné, k vytvoření kódu bez kontextu. Kód bez kontextu má lepší výkon pro mobilní aplikace a je užitečnou technikou pro zamezení zablokování při práci s částečně asynchronním základem kódu. Další informace najdete v tématu Konfigurace kontextu.
  • Používejte úlohy pokračování pro funkce, jako je například zpracování výjimek vyvolaných předchozí asynchronní operací, a zrušení pokračování buď před spuštěním nebo spuštěním. Další informace najdete v tématu zřetězení úloh pomocí souvislých úkolů.
  • Použijte asynchronní ICommand implementaci, pokud jsou asynchronní operace vyvolány z ICommand . Tím je zajištěno, že bude možné zpracovat jakékoli výjimky v asynchronní příkazové logice. Další informace naleznete v tématu asynchronní programování: vzory pro asynchronní aplikace MVVM: příkazy.

Pečlivě vyberte kontejner pro vkládání závislostí.

Kontejnery pro vkládání závislostí zavádějí do mobilních aplikací další omezení výkonu. Registrování a řešení typů s kontejnerem má náklady na výkon z důvodu použití reflexe kontejneru pro vytvoření každého typu, zejména v případě, že jsou pro každou navigaci stránky v aplikaci rekonstruovány závislosti. Pokud existuje mnoho nebo hluboko závislých závislostí, náklady na vytvoření se můžou významně zvýšit. Kromě toho registrace typu, která obvykle probíhá při spuštění aplikace, může mít znatelný dopad na čas spuštění, závisí na používaném kontejneru.

Alternativně lze vkládání závislostí provést tak, že je ručně implementujete pomocí továrn.

Vytváření aplikací prostředí

Xamarin.Forms Aplikace prostředí poskytují navigační prostředí dogmatickým na základě flyouts a karet. Pokud se uživatelské prostředí vaší aplikace dá implementovat pomocí prostředí, je to pro vás užitečné. Aplikace prostředí usnadňují nedostatečné spouštění, protože stránky se vytvářejí na vyžádání v reakci na navigaci, nikoli při spuštění aplikace, ke kterému dochází v aplikacích, které používají "TabbedPage". Další informace naleznete v tématu Xamarin.Forms Shell.

Použít CollectionView místo zobrazení ListView

CollectionView je zobrazení pro prezentování seznamů dat pomocí různých specifikací rozložení. Poskytuje flexibilnější a provádí alternativu k ListView . Další informace naleznete v tématu Xamarin.Forms CollectionView.

Optimalizace výkonu ListView

Při použití nástroje ListView je k dispozici řada uživatelských prostředí, která by měla být optimalizována:

  • Inicializace – časový interval, který začíná při vytváření ovládacího prvku, a jeho ukončení při zobrazení položek na obrazovce.
  • Posouvání – možnost Procházet seznam a zajistit, že uživatelské rozhraní nezpůsobí prodlevu za gesty dotykového ovládání.
  • Interakce pro přidávání, odstraňování a výběr položek

ListViewOvládací prvek vyžaduje, aby aplikace poskytovala data a šablony buněk. Jak se to dosáhne, bude mít velký dopad na výkon ovládacího prvku. Další informace najdete v tématu výkon ListView.

Optimalizace prostředků obrázků

Zobrazení prostředků obrázků může značně zvýšit nároky na paměť aplikace. Proto by měly být vytvořeny pouze v případě potřeby a měly by být vydány, jakmile je aplikace již nevyžaduje. Pokud například aplikace zobrazuje obrázek čtením dat z datového proudu, ujistěte se, že je datový proud vytvořen pouze v případě, že je vyžadován, a zajistěte, aby byl datový proud vydaný, když již není požadován. Toho lze dosáhnout vytvořením datového proudu při vytvoření stránky nebo při aktivaci Page.Appearing události a následným vyřazením datového proudu v případě, že událost je Page.Disappearing aktivována.

Když stahujete obrázek pro zobrazení pomocí Xamarin_Forms _ImageSource_FromUri_System_Uri_ "data-LINKTYPE =" absolutní cesta ">ImageSource.FromUri metodou, zajistěte, aby byla stažená bitová kopie Xamarin_Forms ImageSource.FromUri _UriImageSource_CachingEnabled" data-linktype = "absolutní cesta" >UriImageSource.CachingEnabled vlastnost nastavena na true . Další informace najdete v tématu práce s obrázky.

Další informace najdete v tématu optimalizace prostředků imagí.

Zmenšit velikost vizuálního stromu

Snížení počtu prvků na stránce zajistí rychlejší vykreslování stránky. Existují dva hlavní způsoby, jak to dosáhnout. První je skrýt prvky, které nejsou viditelné. Vlastnost Xamarin_Forms _VisualElement_IsVisible data-LINKTYPE = "absolutní cesta" >IsVisible každého prvku určuje, zda má být element součástí vizuálního stromu, nebo ne. Proto pokud prvek není viditelný, protože je skrytý za jinými prvky, buď odeberte element, nebo nastavte jeho IsVisible vlastnost na false .

Druhým postupem je odebrání nepotřebných prvků. Například následující příklad kódu ukazuje rozložení stránky obsahující více Label objektů:

<StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Hello" />
    </StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Welcome to the App!" />
    </StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Downloading Data..." />
    </StackLayout>
</StackLayout>

Stejné rozložení stránky lze udržovat s menším počtem prvků, jak je znázorněno v následujícím příkladu kódu:

<StackLayout Padding="20,35,20,20" Spacing="25">
  <Label Text="Hello" />
  <Label Text="Welcome to the App!" />
  <Label Text="Downloading Data..." />
</StackLayout>

Zmenšení velikosti slovníku prostředků aplikace

Všechny prostředky, které se používají v rámci aplikace, by měly být uloženy ve slovníku prostředků aplikace, aby se předešlo duplicitě. To vám pomůže snížit množství XAML, které je nutné analyzovat v celé aplikaci. Následující příklad kódu ukazuje HeadingLabelStyle prostředek, který používá rozsáhlou aplikaci a je definován ve slovníku prostředků aplikace:

<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>

Nicméně kód XAML, který je specifický pro stránku, by neměl být součástí slovníku prostředků aplikace, protože prostředky budou následně analyzovány při spuštění aplikace namísto požadavku na stránku. Pokud je prostředek využíván stránkou, která není spouštěcí stránkou, měla by být umístěna do slovníku prostředků pro tuto stránku, takže pomáhá snižovat kód XAML, který se analyzuje při spuštění aplikace. Následující příklad kódu ukazuje HeadingLabelStyle prostředek, který je pouze na jedné stránce, a proto je definován ve slovníku prostředků stránky:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.HomePage"
             Padding="0,20,0,0">
    <ContentPage.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>
    </ContentPage.Resources>
    ...
</ContentPage>

Další informace o prostředcích aplikace naleznete v tématu styly XAML.

Použití vlastního vzoru vykreslovacího modulu

Většina Xamarin.Forms tříd Renderer zpřístupňuje OnElementChanged metodu, která je volána při Xamarin.Forms Vytvoření vlastního ovládacího prvku pro vykreslení odpovídajícího nativního ovládacího prvku. Vlastní třídy Renderer, v každém projektu platformy, pak přepište tuto metodu pro vytvoření instance a přizpůsobení nativního ovládacího prvku. SetNativeControlMetoda se používá k vytvoření instance nativního ovládacího prvku a tato metoda také přiřadí odkaz na ovládací prvek do Control Vlastnosti.

Nicméně v některých případech OnElementChanged může být metoda volána víckrát. Proto, aby se zabránilo nevracení paměti, což může mít dopad na výkon, je nutné při vytváření instance nového nativního ovládacího prvku provést péči. Přístup k použití při vytváření instancí nového nativního ovládacího prvku ve vlastním objektu pro vykreslování je znázorněn v následujícím příkladu kódu:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
  base.OnElementChanged (e);

  if (e.OldElement != null)
  {
    // Unsubscribe from event handlers and cleanup any resources
  }

  if (e.NewElement != null)
  {
    if (Control == null)
    {
      // Instantiate the native control with the SetNativeControl method
    }
    // Configure the control and subscribe to event handlers
  }
}

U nového nativního ovládacího prvku by měla být instance pouze jednou, Control je-li vlastnost nastavena na hodnotu null . Kromě toho by měl být ovládací prvek vytvořen, nakonfigurován a obslužné rutiny událostí, které se přihlásily, když je vlastní vykreslovací modul připojen k novému Xamarin.Forms prvku. Podobně všechny obslužné rutiny událostí, které byly odebírané, by měly být odhlášeny pouze v případě, že je prvek zobrazovací jednotky připojen ke změnám. Při přijetí tohoto přístupu se pomůže vytvořit efektivní provádění vlastního zobrazovacího modulu, který nebrání nevracení paměti.

Důležité

SetNativeControlMetoda by měla být vyvolána pouze v případě e.NewElement , že vlastnost není null a Control vlastnost je null .

Další informace o vlastních zobrazovacích modulech najdete v tématu Přizpůsobení ovládacích prvků na jednotlivých platformách.