MSDN の Xamarin + MvvmCrossでViewとViewModelの対応付けを変更するというコードレシピがあったのですが、少し疑問に思ったので少し調べてみました。
ViewModelからViewを生成する仕組み
以前、MvvmCrossのiOS UniversalアプリでiPadで画面分割を作るでも書いたとおり、ViewModelから対応するViewを生成しているのはIMvxViewPresenterです。ですので、ViewModelとViewの関連づけを変えたい場合はここからの動きを変更するのが正攻法で、MvxAndroidViewPresenter.Show(MvxViewModelRequest) や MvxAndroidViewsContainer.ViewModelFromRequest、MvxAndroidViewsContainer.GetIntentFor などでフックする形の方が本来のやり方です。
おそらくコードレシピで書かれている内容では、画面遷移を発生させるとおかしくなってしまうのではと思いました(未検証ですが)。
そもそも、このような方法をとらないといけない場面は通常起こりえません。検証コードを書いていましたが、手間の割に得られるものが少なすぎると判断して中止しました。この方法が本当に必要なのか再度検討してください。
MainLauncher = false にしないと動かない?
Xamarin.Android のプロジェクトを新規作成して MvvmCross をプロジェクトに導入すると、その時点でプロジェクトには3つの Activity が存在することになります。
このうち、Xamarin Studio のテンプレートが作成する MainActivity と、MvvmCross の起動ポイントである SplashScreen は、ActivityAttribute にアプリの最初の Activity であることを示す MainLauncher = true というプロパティが指定されています。このため、二つ MainLauncher があると、同じアプリの中に 2 つアプリが存在するという形になり、ランチャに 2 つアイコンが登録されます。
つまり、MainActivity.cs が以下の場合
// using namespace Test02.Droid { [Activity( Label = "Test02.Droid (Main)" , MainLauncher = true , Icon = "@drawable/icon")] public class MainActivity : Activity { // ... } }
そして、SprashScreen.cs が以下となっている場合
// using namespace Test02.Droid { [Activity([f:id:iseebi:20150301171745p:plain] Label = "Test02.Droid (Splash)" , MainLauncher = true , Icon = "@drawable/icon" , Theme = "@style/Theme.Splash" , NoHistory = true , ScreenOrientation = ScreenOrientation.Portrait)] public class SplashScreen : MvxSplashScreenActivity { // ... } }
実際にアプリがインストールされると1つのapkに対して2つのアプリがランチャに登録されます。
この状態だと、Xamarin Studioからは実行するときに SplashScreen から起動しなければならないはずが、MainActivity から起動してしまいます。
MvvmCross を Android プロジェクトに導入した後は、Xamarin Studio のテンプレートで生成される以下のファイルは不要になるので削除しましょう。
- Resources/layout/Main.axml
- MainActivity.cs
また、この ActivityAttribute などは最終的に AndroidManifest.xml に変換されてアプリに埋め込まれます。どのようなものが使えるかについてはa. AndroidManifest.xml ファイル - ソフトウェア技術ドキュメントを勝手に翻訳や Working with AndroidManifest.xml | Xamarinなどを一読した方がいいと思います。