【この記事は旧ブログから移転したものです】

先日リリースした「診断ビューアー」の技術的な話です。

今回はXamarinでとりあえずなにか作ってみようということで軽めに1本作りました。

しかし、いろいろ調べながら作っていたため、技術的にはかなり大きな収穫があったと思います。

iOSとAndroidの見た目の違い

Xamarin.Formsでクロスプラットフォーム開発をして、いざiOSとAndroidでビルドして動かしてみると、その見た目の違いがかなり気になります。

というのも標準ではiOSは白背景、Androidは黒背景でコントロールもその色をベースに作られているので、Xamarin.Formsでコードを共通化しても、見た目が全然違います。

これは、Android側を白ベースにしてiOSに近づけることで解決しました。

具体的には、ソリューション内のAndroidプロジェクトの中にあるMainActivity.csの以下のように変更しました。

[Activity(Label = "診断ビューアー",
 Icon = "@drawable/icon",
 MainLauncher = true,
 ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
 Theme = "@android:style/Theme.Holo.Light")]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity {
    protected override void OnCreate(Bundle bundle) {
        ...
    }
}

MainActivityクラスの属性の

Theme = "@android:style/Theme.Holo.Light"

が今回変更したところです。 これでAndroidアプリが白ベースになります。

非同期処理について

ただの知識不足だったんですが、Commandasync/awaitが使えることがわかったので、 できるところはすべて非同期処理に書き換えて、UIをブロックしないようにしました。

new Command(async () => {
    await Task.Run(() => /*時間のかかる処理*/);
};

このように書くことで既存の同期処理を非同期処理に書き換えることができます。

シングルトンなModel

今回はXamarinに慣れる意味もあって、極力MVVMパターンを守りました。 そんななかで設計上インスタンスが何個もあるとまずいModelがありました。 最初はstaticなクラスにしようと思ったのですが、 何となく気持ち悪かったのでteratailで質問したところ無事解決することができました。

C# - MVVMでModelを複数のViewModelから利用する|teratail

MVVMにおいて共有インスタンスはシングルトン化するのが一般的だと思います。

とのことなので、シングルトンにて実装しました。

ObservableCollectionの更新処理

ViewModelのObservableCollectionをViewにバインドしているのですが、 データの更新処理でデータをすべて書き換えるときに最初は、

void UpdateData() {
    // ObservableCollection を初期化
    this._items = new ObservableCollection<Model>();

    // 更新処理
    foreach (var d in GetDate()) {
        this._item.Add(d);
    }
}

このようにしていたのですが、インスタンスを初期化してしまうとバインドが切れてしまう(?)ようでうまく動きませんでした。 そこで以下のようにしたところうまくいきました。

void UpdateData() {
    // ObservableCollection をクリア
    this._items.Clear();

    // 更新処理
    foreach (var d in GetDate()) {
        this._item.Add(d);
    }
}

インスタンスを初期化せずに要素を全部消して、その上で一から追加していく方法です。 確かによくよく考えれば当たり前な気もしますが….

まとめ

他にも様々な発見がありましたが、ブログに載せるのはこれぐらいにしたいと思います。 また今回はViewからの画面遷移になってしまったので、 MVVMに忠実にViewModelからViewModelへの遷移を実装できたらと思います。 PrismというMVVMフレームワークを使えばできるらしいのですが………。