shuhelohelo’s blog

Xamarin.Forms多めです.

dot net conf 2020 xamarin メモ

動画 www.youtube.com

サンプルコード github.com

Keynote : Xamarin All The Things

AndroidのProfiled AOT

Profiled AOTはStartup Speedが速く(AOTについで)でAPK SizeがAOTよりも小さい(Normalよりは大きい).

バランスがいい.

Type Startup Speed APK Size
Normal 2s914ms 16.1 MB
AOT 1s18ms 34.6 MB
Startup Tracing 1s518ms 20.1 MB

Visual StudioAndroidプロジェクトのProfileを開く.

左ペインからAndroid Optionsタブを選択し,Enable Startup Tracingという項目にチェックをつける.

f:id:shuhelohelo:20200408181155p:plain

試してみた.

  • チェックなし.8.3MB.

f:id:shuhelohelo:20200408195120p:plain

  • チェックあり.8.4MB.

f:id:shuhelohelo:20200408195909p:plain

Xamarin.Formsデモ

FlyMeアプリケーション.

All Things Xamarin.Forms Shell

Shellは

  • アプリケーションの構造を宣言的に記述できる
  • ナビゲーションをシンプルにする
  • カスタマイズ性に優れる
  • 作りたいアプリを素早く開発できる

Shellの見た目を設定する

細かく変更できる. f:id:shuhelohelo:20200411012517p:plain

ドロワーメニューの見た目を設定する

DataTemplateをResourceDictionary内に定義して,それを使う.

f:id:shuhelohelo:20200411012622p:plain

StyleClass (Xamarin.Forms 4.6以降)

Shellに限らない.すべての要素に有効な機能.

HTML,CSSのclassのようにスタイルを適用できる. 複数適用できるのが特徴.

docs.microsoft.com

追記

ShellのFlyoutItemに関するスタイルの指定については以下のShell Fly-out Stylingの項目を参照する.

devblogs.microsoft.com

Tabの見た目を設定する

f:id:shuhelohelo:20200411012938p:plain

Shellのナビゲーション(遷移)

  • 遷移先に名前をつける.
<Tab Title="Details" Route="Details"....
  • どこからでも遷移できる
await Shell.Current.GoToAsync("//Details");
  • ページとRoutingを登録しておける
Routing.RegisterRoute("ModalPage", typeof(ModalPage));
  • Deep link ナビゲーション
await GoToAsync("//Details/ModalPage");

文字列でナビゲーションできる.

アプリから離脱しても,その時のURLを記録してさえ於けば,復帰も簡単.

モーダルページ

Shell.PresentationMode="Modal"
await Shell.Current.GoToAsync("ModalPage");

docs.microsoft.com

Search Handler

これ使いたいな.

BackButtonBehavior

TextOverrideで戻るボタンのテキストを変更できる IconOverrideで戻るボタンのアイコンを変更できる

Shellの特徴

ContentPage,MasterDetailPage,NavigationPage,TabbedPageをまとめてShellで置き換えることができる.

Shell.TitleViewでTitleBarのUIを作成できる.

Shellの今後

  • 3rdパーティ製のMVVMサポート(Prism,FreshMVVM,RxUIなど)
  • TitleViewの修正
  • すべてをテンプレート化
  • デュアルスクリーンをサポート
  • パフォーマンスの向上

    QA

    GoToはAsyncだけれど,OnNavigatedなどはAsyncではない.

Spectacular Components for Xamarin Apps

MacOSもXamarin.Formsで?

  • Expressive
  • MVVM Atom
  • HttpTracer
  • AnyBind
  • TinyInsights
  • Shiny

Shinyの紹介

  • Background Task
  • Notification

Resizetizer

通常,様々なディスプレーサイズに合わせて,各画像ごとに複数のサイズを用意しなければならない.

このライブラリは画像を一つ用意しておけば,それらを自動的に生成してくれるもの?

Control Vender製のコントロールについて紹介

Communityによって提供されるコントロール

  • Magic Gradients
  • Color Picker Control
  • XamAnimation
  • Sheet Control
  • Xamlly
  • PancakeView

DebugRainbowsの紹介

開発のための機能がある - 各コントロールに色をつけて領域をわかりやすくする - 格子を表示して,コントロールの位置をわかりやすくできる <- Xamarin.Forms.DebugRainbowsだ.これ

github.com

PancakeViewの紹介

FrameやImage的なものの枠を三角形にしたり1つの角だけ丸めたり,色々できる.

f:id:shuhelohelo:20200410214748p:plain

SkiaSharp

SkiaSharpを使ったライブラリの紹介

  • Balloony
  • Magic Gradients
  • Microchart
  • Mapsui
  • Aurora Highlights
  • eliteKit
  • Draw2D

Sharpnado

  • CollectionViewのアイテムの入れ替えなどができる

Task Loaderとは?

Building Beautiful Apps with Xamarin.Forms

おしゃれなアプリとは?

  • とても主観的なもの
  • トレンドに左右される
  • 無意識に
  • 重要なものの不足を補えない
  • すごい開発者がすごいデザイナとはいえない

なんで評判がよくない?

  • シンプルなデータ入力アプリに向いているというマーケティングを行った
  • 過去の経験
  • 「Forms」という言葉の印象

おしゃれUIの要素

  • グラデーション
  • SkiaSharp
  • MagicGradients
  • PancakeView
  • Built-in Xamarin Forms Gradients(そのうち)
  • iOSでは好きなようにできる
  • Androidでは制限がある
  • フォント,アイコン
  • Google Fonts
  • FontAwesome などなど
  • 色(の組み合わせなど)を生成するツールを使う
  • 動き,アニメーション
  • Micro Animation
  • Lottie
  • Xamarin.Forms built-in animation
  • Xamanimation
  • Page Transitions
  • Xamarin.Plugin.SharedTransition

おしゃれさのためだけではない

Styleを使おう!

UIの再利用性を高めるためにStyleを使う.

Button,色,フォントなどなどを個別のファイルに分けてStyleを定義しておく.

f:id:shuhelohelo:20200409113917p:plain

練習の仕方

  • オンラインで色々探してインスピレーションを得る
  • 実際に試してみる
  • 後はやるだけ

具体的には

  • デザインをまとまりごとに分ける
    • どのように構成したらいいかを考える

サンプル

github.com/sthewissen/FocusOnXamarin

GridでRowDefinition

作れなければ,それっぽく見せればいい

If you can't make it, fake it

おすすめのサイト,パッケージやフォントなどのリソース

f:id:shuhelohelo:20200410213701p:plain

Xamarin Productivity to the Max

Code Build Deploy Iterate この繰り返しを迅速に行うには.

  • IntelliCode

Xamarin.Forms.Visual.Materialとは. iOSAndroidで同じMaterialDesignな見た目に統一することができる.

完全ではない.

docs.microsoft.com

Testing Your Xamarin Apps

テストの階層は上から順に以下のとおり.

  • UI Test エンドユーザーの視点でのテスト.Viewに対して行う.

  • Automated Service Test Serviceが期待どおりに動作して,正しいデータを返すかをテストする.

  • Automated Unit Test 機能の動作を確認するためのテスト.ViewModelに対して行う.

FIRSTの原則

  • Fast テストは遅いものだけれども,遅くならないように書かなければならない.

  • Independent 他のテストを呼び出してはいけない.

  • Repeatable アクセストークンのような定数を使ってはいけない.MockサーバーやMockサービスを使う

  • Self-validating Assertsを使う

  • Timely 複雑にならないようにする.そのためにはアクションを複数のテストに分ける必要があるかもしれない.

Unitテストの基本的な構成

AAAパターンで書く.

  • Arrange
  • Act
  • Assert

テスト対象

public int MySum(int a, int b)
{
    return a + b;
}

テストコード

[Test]
public void TestMySum()
{
    //Arrange
    int a = 5;
    int b = 7;

    //Act
    int result = MySum(a, b);

    //Assert
    Assert.AreEqual(12,result);
}

テスト条件を設定(Arrange)して,実行(Act)して,判定(Assert)する.

なぜテストをしなければならないのか

  • システムの機能をテストする
  • アプリケーションの各部分を一度にテストする
  • アーキテクチャをシンプルに保つ
  • バグを早期に発見する
  • リグレッションを避ける

テストしよう

Mock(Moq)サービスを使ってインターフェースのインスタンスを作成する.

ViewModelを使っている場合,テストするときにBinding,JSON parsers,PluginsやXamarin.Formsの機能などXamarin開発チームによってテストされているものについては考える必要はない.

自分のコマンドやロジックをViewModel越しにテストする.

選択したテスティングフレームワークに従ってテストを書くこと.

IntelliTestが役に立つよ!

すべてにInterfaceを

アプリに様々なプラグインやパッケージをインストールするよね.Xamarin.Essentialsとか.

例えばXamarin.Essentialsを使うなら,IXamarinEssentialsを作ってプロパティとメソッドだけを公開すると,柔軟性が高くなる.

Unit Test Demo

github.com

UI Test

BDDアプローチ

Behavior Driven Development

技術的な言葉を使わずに誰もがわかる言葉でテストを記述する.(例えば,Gherkinのようなドメイン記述言語など)

例示を用いて議論を行うことを通じて,どのようなソフトウェアを作るのかについて共通の理解を構築するためのアプローチ.

例えば:

As a [Role]
I want [Feature]
So that [Benefit]

Roleとして
Benefitを得るために
Featureがほしい

つまり,「誰が何のためにどんな機能がほしい」のかを明確にするということか.

これに従うと:

As a [Registered User]
I want [to be able to login]
so that [I can see the Application]

Scenario 1: User is able to log in

Given that I am a registered user,
when I enter the username 'Codrina'
and password 'ladybug',
then I should see the first screen of the app.

UI Test Demo

UIテストをどうするか.

Going Reactive with Reactive Extensions & UI

ReactiveUIについて.

よく見るこのイベントハンドラ.

SearchBar.TextChanged += (sender, args) => { };
textChangedEvents
    .Throttle(TimeSpan.FromMilliseconds(750),RxApp.TaskpoolScheduler)
    .Select(x => x.NewTextValue.Trim())
    .DistinctUntilChanged()
    .Where(x => !string.IsNullOrWhiteSpace(x))
    .ObserveOn(RxApp.MainThreadScheduler)
    .InvokeCommand(this, x => x.ViewModel.Search)
    .DisposeWith(ViewBindings);

ロジックのすべてをコンストラクタにまとめることができる.

テキスト

kent-boogaart.com

github.com/kentcb

イベントを普通に使うのであれば役に立つよ.

All Things Xamarin.Forms Shell

www.youtube.com

Developing Performant Xamarin Apps

Improve Xamrin.Forms App Performance という動画があるのでチェックするように.

Performance Optimizations

  • 起動時にすべてのServiceを開始/登録しないこと.可能な限りLazyロードする.
  • montemagnoさんのTurnip TrackerでLazy使ってる.
  • 起動時にすべてのデータをダウンロードしない.
  • User Experienceについて考える
  • Lottieつかったり
  • iOS: Launch Storyboard
  • Android: Splash Screen Activity

Androidの起動時について

  • AOT with startup tracingを使う
  • Custom Profiles with Startup Tracingを使う.

Async/Awaitのベストプラクティスを使う

  • 同時に実行できるところで,処理を順次行わないようにする.
  • すべてのTaskが完了することを不必要に待たないようにする
  • ループの中でTask.Runを使わない
  • Cancellation tokensを使うこと

順次処理と並行処理

  • 例1: f:id:shuhelohelo:20200420124905p:plain

Okay Codeではループの中でawaitを使って処理を一つずつ完了している.

Better CodeではWhenAllを使ってすべての処理を同時に処理している.

  • 例2: f:id:shuhelohelo:20200420124940p:plain

Okay CodeではWhenAllを使ってすべてのリクエストの結果が得られるまでawaitして,結果のリストからオブジェクトを取得している.

Better CodeではWhenAnyを使って,結果が得られたものから直ちにオブジェクトを取得.

こちらの方が効率が良いとのこと.

Cancellation tokens

Taskのキャンセルに使用する.

tokenを作って,それをTaskの実行時に渡す.そして,Cancel()メソッドを実行すると,Taskの実行を終了させることができる.

var cts = new CancellationTokenSource();
var token = cts.Token;

Task.Run(async() => await someLongRunningAction(),tokens);

cts.Cancel();

しかし,Cancelのハンドリングは以下のように並行処理の中にtokenを介してThrowIfCancellationRequested()を記述しておく必要がある.

Cancelされた後に,この記述の位置に来たときにTaskがキャンセルされる.

var cts = new CancellationTokenSource();
var token = cts.Token;

Task.Run(async() => await {
        for (int i = 0; i<3; i++){
            token.ThrowIfCancellationRequested();
        }
    },tokens);

cts.Cancel();

参考: f:id:shuhelohelo:20200420131746p:plain

Event Handlers

  • イベントハンドラーのDetachとObserverのDisposeを必ず行うこと.
    • モリーリークを防ぐために,イベントのUnsubscribeを行い,匿名デリゲートの使用を避けること.
public class Subscriber :IDisposable
{
    readonly Publisher publisher;
    EventHandler handler;

    public Subscriber(Publisher publish)
    {
        publisher = publish;
        handler=(sender,e)=>{
            Debug.Writeline("The publisher notified the subscriber of an event.");
        };
        publisher.MyEvent+=
    }

    public void Dispose()
    {
        publisher.MyEvent -=handler;
    }
}
public class Publisher
{
    public event EventHandler MyEvent;

    public void OnMyEventFires()
    {
        if(MyEvent != null){
            MyEvent(this,EventArgs.Empty);
        }
    }
}

public class Subscriber: IDisposable
{
    readonly Publisher;

    public Subscriber(Publisher publish)
    {
        publisher=publish;
        publisher.MyEvent+=OnMyEventFires;
    }

    void OnMyEventFires (object sender,EventArgs e)
    {
        Debug.Writeline("...");
    }

    public void Dispose ()
    {
        publisher.MyEvent -= OnMyEventFires;
    }
}

データのロード

  • ローカルデータをまず読み込む
  • Webとのデータのやり取りを最小限に抑える.
  • ただのラベルやタイトルといった静的なデータをバインドしないこと.

Profilerを活用しろ

  • 確認する点
  • モリーリーク,
  • 大きな画像
  • 大きなオブジェクトグラフ
  • 広いスコープ
  • 相互参照

  • 計測する点

  • 起動時間
  • 実行時間
  • メモリ消費
  • CPU利用状況
  • ネットワーク状況
  • I/O状況

Icon, Image, Asset

ディスプレイの解像度ごとに画像の解像度も最適化するのが良い.

でも,それを手動で行うのは手間なので,ResizetizerNTというNugetパッケージがある.

レイアウトについて

docs.microsoft.com

  • レイアウトを入れ子にしない
  • GridでAutoを使わない
  • ListViewやCollectionViewではDataTemplateを使うこと
  • AndroidではAppCompatを使うこと

フォントについて

  • フォントを
  • 画像を使わずに,アイコンフォントを使うこと
  • 非表示のタブページの扱いに気をつけること

参考: f:id:shuhelohelo:20200421022434p:plain