MvvmCrossのServiceを使って共通オブジェクトを作る

MvvmCrossには IoCコンテナ機能が備わっており、アプリ内で使う共有オブジェクトを自動的に管理してくれるようになっています。

主な仕組みとして、Serviceというものが用意されており、決まった名前でオブジェクトを定義すると、自動的に読み込まれるようになっています。また、プラグインで提供される各種オブジェクトも、IoCコンテナを経由して取得します。

本稿では、IoCコンテナの基本的な使い方を紹介します。なお、Hot Tuna Starter Packが導入されたプロジェクトが準備されているという想定です。

IoCコンテナに登録されるオブジェクト(Service)を作る

CoreプロジェクトにServicesフォルダを作り、その中に最後が「Service」で終わるインターフェイスと、それを実装するクラスを用意します。

SampleService

using System;
using Cirrious.CrossCore;

namespace CrossSample.Core.Services
{
    /// <summary>
    /// サンプルサービスのインターフェイス
    /// </summary>
    public interface ISampleService
    {
        void SampleMethod(string message);
    }

    /// <summary>
    /// サンプルサービスの実装クラス
    /// </summary>
    public class SampleService : ISampleService
    {
        public void SampleMethod(string message)
        {
            Mvx.TaggedTrace("SampleService", "Sample message: {0}", message);
        }
    }
}

App.cs 内にある、下記のコードが起動時に末尾が「Service」で終わるクラスを探して、IoCコンテナにすべて登録するようになっています。

public override void Initialize()
{
    // この行でServiceで終わるクラスを探して一括登録している
    CreatableTypes()
        .EndingWith("Service")
        .AsInterfaces()
        .RegisterAsLazySingleton();
        
    RegisterAppStart<ViewModels.FirstViewModel>();
}

IoCコンテナ内のオブジェクトをViewModelやServiceで使う

IoCコンテナ内にあるオブジェクトは、アプリ内ではじめて使われる場合にインスタンスが生成され、すでにインスタンスがある場合はそのインスタンスが利用されます。

ViewModelやServiceのコンストラクタに、IoCコンテナに入っているインターフェイスの引数を追加すると、インスタンス生成時にセットされるようになります。

渡された入ってきたインスタンスをプライベートフィールドやプロパティに確保しておいて、そこからアクセスするようにします。

using Cirrious.MvvmCross.ViewModels;
using CrossSample.Core.Services;

namespace CrossSample.Core.ViewModels
{
    public class FirstViewModel : MvxViewModel
    {
        private readonly ISampleService SampleService;

        public FirstViewModel(ISampleService sampleService)
        {
            // 初期化時に自動的に取得して指定されるので、受け取ります。
            SampleService = sampleService;
        }

         void Test()
        {
            SampleService.SampleMethod("Test called");
        }
    }
}

IoCコンテナを使ってオブジェクトを生成する

たとえば、IoCコンテナ以外のモデルオブジェクトで使いたいというときに使います。下記のようにモデルクラスを定義します。

using System;
using CrossSample.Core.Services;

namespace CrossSample.Core.Models
{
    public class LetterItem
    {
        private readonly ISampleService SampleService;

        public LetterItem(ISampleService sampleService)
        {
            SampleService = sampleService;
        }
    }
}

このように作ったクラスは、Cirrious.CrossCore.Mvx.IoCConstruct<T>() でオブジェクトを作成した際に、ViewModelやServiceと同じようにコンストラクタインスタンスが渡されるようになります。

// using Cirrious.CrossCore;
var item = Mvx.IoCConstruct<LetterItem>();

IoCコンテナ内のオブジェクトをその場で解決する

また、Mvx.Resolve<T>()を使って直接依存を解決する方法もあります。ただし、Singleton的になってあんまりよろしくないので、最後の手段としたほうがいいです。

var sampleService = Mvx.Resolve<ISampleService>();