2017-03-07 9 views
1

まず、SingleInstanceについていくつかの質問を読んだことがありますが、依然として私に役立つ直接回答は見つかりません。それは私が何かを逃した場合、私は謝罪した。Autofac SingleInstance()とXamarinフォーム

は、ここに私の質問です:

私は、iOSおよびAndroid向けXamarinフォームアプリケーションを構築しています。私はPCLに1つのAppInitializerクラスを持っていて、そこで私はすべてのインターフェイス依存関係をAutofacを使って登録しています。次に、ビルダーからのコンテナをappクラスの静的プロパティとして割り当てます。私が遭遇する問題は、.SingleInstance()ですべてを登録している間は、実際には単一インスタンスを取得していないということです。

初期化ロジックの例:

var builder = new ContainerBuilder(); 
builder.RegisterType<ErrorHandler>().SingleInstance().As<IErrorHandler>(); 
… 
builder.RegisterType<MemberViewModel>().SingleInstance().As<IMemberViewModel>(); 
… 
AppContainer.Current = builder.Build(); 

私はAutofacが私のコンストラクタで解決のインターフェイスを処理せています。たとえば:

public MemberViewModel(ISettingsViewModel settings, IErrorHandler errorHandler, …) : base(settings, errorHandler){…} 

私はその後、以下のようにページ上で述べたモデルを使用します。

例ページの使用:

public ProfilePage() 
{ 
    InitializeComponent(); 
    var displayModel = Model.CurrentMember; 
    … 
} 
… 
**public IMemberViewModel Model => 
AppContainer.Current.Resolve<IMemberViewModel>();** 

この例では、私はすぐに到着する前にModel.CurrentMemberのプロパティを設定しますこのページで私はブレークポイントを設定し、これが起こっているという事実を知っています。しかし、モデルのインスタンスを解決すると、CurrentMemberのプロパティはnullになります。

ここで何か間違っているのですか、バグがありましたか?

-edd- 私はAutofacを使用していることを明確にしました。

-edit 2- 詳細を追加します。

私のIMemberViewModelクラスの実装には、現在のメンバーと呼ばれる観測可能なオブジェクトを含むさまざまなプロパティがあります。それは以下のように宣言されています:IMemberViewModelの実装に

public class MemberViewModel : ViewModelBase, IMemberViewModel 
{ 
    … 
    (see constructor above) 
    … 
    public MemberDisplay CurrentMember => 
     m_CurrentMember ?? (m_CurrentMember = new MemberDisplay()) 

私はCURRENTMEMBER上のさまざまなプロパティを設定する方法があります。

動作の順序はこれです:

エンドユーザはメンバーの画像をタップします。これは、IMemberViewModel実装の(理論上)シングルトンインスタンスに対するコマンドを起動します。このコマンドは、そのメンバーのデータをロードするためのAPIへの非同期呼び出しを待つ非同期タスクを実行します。そのデータがロードされ、プロパティがCurrentMemberに設定されると、アプリはプロファイル画面にナビゲートします。プロファイル画面はIMemberViewModelを解決します(上記)。

予想される動作:IMemberViewModelの解決されたインスタンスからCURRENTMEMBER上 プロパティは、単に負荷データ方式から設定された値に設定されています。この予想は、IMemberViewModelのインスタンスが1つあると仮定することによって発生します。

実際の動作: CURRENTMEMBERのプロパティは、など、そのデフォルト値でヌルすなわちString.Emptyを、0、ある

ここで奇妙なことは、これはすべてのモデルには起こらないということです。私は同じ画面上で同じ方法で解決しているメッセージモデルを持っており、それはうまくいくようです。

+1

あなたが 'Model.CurrentMember'のプロパティをページに渡す前に設定したとしたら、同じコンテナから' IMemberViewModel'を解決してプロパティを設定するのですか? –

+0

モデル上のCurrentMemberは、いくつかの文字列プロパティを持つ観察可能なオブジェクトです。 IMemberViewModelの実装でロードデータ呼び出し内からこれらの文字列(名前など)を直接設定しています。私の期待は、IMemberViewModelを解決すると、実装の単一のインスタンスが得られるということです。代わりに、私はその実装の新しいインスタンスを取得しています。質問をより詳細に更新します。 – Kerfuffle

+0

@MickaëlDerriey。私はあなたの返信であなたにタグを付けるのを忘れました。 – Kerfuffle

答えて

0

この問題は、すべてを初期化する方法が原因であることが判明しました。後世のために、私は何が起こっているのか、それを防ぐために何をしたのかを簡単に説明します。

前のアプリケーションフロー:

  • のApp &コンストラクタが呼ばれるオープンします。上記の初期化ルーチンを呼び出します。
  • ユーザーログイン。
  • IMemberViewModelの最初のインスタンスは、静的コンテナを使用して解決されました。
  • メッセージをプッシュ通知権限
  • をユーザーに尋ねるポップアップ表示ユーザーが回答を選択した後、この現象が発生すると、アプリのOnSleepは(iOS版)
  • と呼ばれ、OnResumeが呼び出されます。
  • OnResumeは初期化ルーチンを呼び出します。
  • 新しいコンテナが作成されました。
  • データをロードする呼び出しは古いコンテナで行われ、新しいページは新しいコンテナを参照します。
  • 上記のように問題が発生します。

流れに訂正:

まず、私は初期化呼び出しが履歴書上で行われる必要があり、および/またはアプリのコンストラクタで行われた場合には起動しません伝えることができるものから。他のアプリがメモリスペースを必要としているためアプリが「殺された」場合、次回の起動時に新しいバージョンのアプリが作成されます(Android Activity LifecycleiOS App Lifecycleを参照)。

第2に、私は妄想的で、傷つけることもないので、アプリの初期化ルーチンで、コンテナが存在するかどうか、インターフェイスが既に登録されているかどうかを確認しています。

public static void Init(ISetup setup) 
{ 
    if (Container != null && IsModelRegistered()) return; 

    RegisterDependencies(setup); 
    … 
} 

private static bool IsModelRegistered() 
{ 
    return Container.IsRegistered<IMemberViewModel>(); 
} 
関連する問題