升级到6.0版后,MvvmCross App无法启动

时间:2018-04-16 19:40:56

标签: xamarin.android mvvmcross

我将我的应用程序升级到MvvmCross 6.0版。现在它进入启动画面并且不执行任何其他操作。通过查看控制台,我可以看到服务正在启动。这是我的app.cs:

public class App : MvxApplication
{
    public override void Initialize()
    {
        MPS.ApplicationName = Settings.ApplicationName;
        EventLog.ApplicationName = Settings.ApplicationName;
        BlobCache.ApplicationName = Settings.ApplicationName;

        CreatableTypes()
            .EndingWith("Service")
            .AsInterfaces()
            .RegisterAsLazySingleton();

        CreatableTypes()
            .EndingWith("Singleton")
            .AsInterfaces()
            .RegisterAsSingleton();

        //RegisterAppStart(new CustomAppStart());
        //RegisterNavigationServiceAppStart<LoginViewModel>();
        RegisterAppStart<LoginViewModel>();
    }

}

这是非常基本的。我已经转换为新的导航系统,因此转换为RegisterNavigationServiceAppStart。那将不再解决,所以我回到了直接的RegisterAppStart。启动画面出现然后停止。如果重要,splashscreen.cs如下:

[Activity(
    Label = "@string/ApplicationName"
    , MainLauncher = true
    , Icon = "@drawable/icon"
    , Theme = "@style/Theme.Splash"
    , NoHistory = true)]
    //, ScreenOrientation = ScreenOrientation.Landscape)]
public class SplashScreen : MvxSplashScreenActivity
{
    public SplashScreen()
        : base(Resource.Layout.SplashScreen)
    {
    }
}

它非常香草,但我知道事情已经发生了变化。我的setup.cs如下:

public class Setup : MvxAndroidSetup
{
    //public Setup(Context applicationContext)
    //    : base(applicationContext)
    //{
    //}

    protected override IMvxApplication CreateApp()
    {
        return new App();
    }

    //protected override IMvxTrace CreateDebugTrace()
    //{
    //    return new DebugTrace();
    //}

    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {
        return new MvxAppCompatViewPresenter(AndroidViewAssemblies);
    }

    protected override void FillValueConverters(IMvxValueConverterRegistry registry)
    {
        base.FillValueConverters(registry);
        registry.AddOrOverwrite("DateToStringConverter", new DateToStringConverter());
        registry.AddOrOverwrite("FloatToStringConverter", new FloatToStringConverter());
        registry.AddOrOverwrite("DecimalToStringConverter", new DecimalToStringConverter());
        registry.AddOrOverwrite("BoolToViewStatesConverter", new BoolToViewStatesValueConverter());
        registry.AddOrOverwrite("ShipmentToOriginConverter", new ShipmentToOriginConverter());
        registry.AddOrOverwrite("ShipmentToDestinationConverter", new ShipmentToDestinationConverter());
        //registry.AddOrOverwrite("CustomName2", new AnotherVerySpecialValueConverter("Summer"));
    }

    protected override void FillTargetFactories(MvvmCross.Binding.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
    {
        base.FillTargetFactories(registry);
        registry.RegisterCustomBindingFactory<EditText>("FocusText",
                                                  textView => new MvxEditTextFocusBinding(textView));
        registry.RegisterCustomBindingFactory<TextView>("FocusChange",
                                                  textView => new MvxTextViewFocusChangeBinding(textView));
        //registry.RegisterCustomBindingFactory<MvxSpinner>("ItemSelected",
        //                                          spinner => new MvxSpinnerItemSelectedBinding(spinner));
    }

    protected override IEnumerable<Assembly> AndroidViewAssemblies => new List<Assembly>(base.AndroidViewAssemblies)
    {
        typeof(MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView).Assembly
    };

}

我对它做的唯一改变是删除构造函数。根据6.0版的文档,构造函数不再有参数,所以我没有理由调用它。有人可以帮忙吗?

**更新**

我添加了一个MainApplication.cs,如下所示:

[Application]
public class MainApplication : MvxAppCompatApplication<Setup, App>
{
    public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
    }
}

这让我超越了启动画面,但挂起了LoginViewModel的Initialize。

*记录*

也许这会有所帮助。以下是事件日志条目:

2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Primary start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: FirstChance start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: PlatformServices start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: MvvmCross settings start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Singleton Cache start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewDispatcher start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Bootstrap actions
2018-04-17 12:17:07 [TRACE] (MvvmCross.Logging.MvxLog) No view model type finder available - assuming we are looking for a splash screen - returning null
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: StringToTypeParser start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: CommandHelper start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: PluginManagerFramework start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Create App
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: NavigationService
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Load navigation routes
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: App start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Application Initialize - On background thread
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewModelTypeFinder start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewsContainer start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Views start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: CommandCollectionBuilder start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: NavigationSerializer start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: InpcInterception start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: InpcInterception start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: LastChance start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Secondary end
2018-04-17 12:17:08 [TRACE] (MvvmCross.Logging.MvxLog) AppStart: Application Startup - On UI thread

我进一步追踪它。它挂在视图模型中的Initialize()上。我创建了一个测试来演示:

public class FirstViewModel : MvxViewModel
{

    public FirstViewModel()
    {
        Task.Run(async () =>
        {
            var l = await ListDataSource.GetLocations();
            var m = l;
        });
    }

    public async override Task Initialize()
    {
        await base.Initialize();
        var l = await ListDataSource.GetLocations();
        var m = l;
    }

}

如果我在两个var m = l上设置断点,它将到达构造函数中的断点,但永远不会到达Initialize中的断点。 GetLocations是:

    public async static Task<LocationList> GetLocations()
    {
        ListServiceClient client = NewClient();

        LocationList ret = null;
        bool TryCache = false;

        try
        {
            //ret = await client.GetLocationListAsync();
            ret = await Task<LocationList>.Factory.FromAsync((asyncCallback, asyncState) => client.BeginGetLocationList(asyncCallback, asyncState),
               (asyncResult) => client.EndGetLocationList(asyncResult), null);

            client.Close();
            await BlobCache.LocalMachine.InsertObject("Locations", ret, DateTimeOffset.Now.AddDays(Settings.CacheDays));
        }
        catch (TimeoutException ex)
        {
            client.Abort();
            EventLog.Error(ex.ToString());
            TryCache = true;
        }
        catch (CommunicationException ex)
        {
            client.Abort();
            EventLog.Error(ex.ToString());
            TryCache = true;
        }
        catch (Exception ex)
        {
            EventLog.Error(ex.ToString());
            TryCache = true;
        }

        if (TryCache)
        {
            try
            {
                ret = await BlobCache.LocalMachine.GetObject<LocationList>("Locations");
            }
            catch (KeyNotFoundException)
            {
                ret = null;
            }
        }

        return ret;
    }

如果在Client.Close()上设置断点,如果从构造函数调用它将会到达那里,但如果从Initialize调用则不会。

4 个答案:

答案 0 :(得分:6)

我的问题是双重的。首先,当您使用Android升级到6.0版时,您现在必须包含MainApplication.cs,如下所示:

[Application]
public class MainApplication : MvxAppCompatApplication<Setup, App>
{
    public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
    }
}

如果没有这个,你会被困在SplashScreen上。其次,您需要知道您显示的第一个ViewModel中的Initialize必须是同步的。正如@Ale_lipa所提到的,一位MvvmCross作者撰写了一篇博客文章,解释了为什么会这样做以及如何处理它。

https://nicksnettravels.builttoroam.com/post/2018/04/19/MvvmCross-Initialize-method-on-the-first-view-model.aspx

简而言之,如果您使用的是SplashScreen,并且您确实需要将第一个ViewModel的Initialize作为Async,则可以按如下方式添加CustomAppStart:

public class CustomMvxAppStart<TViewModel> : MvxAppStart<TViewModel>
     where TViewModel : IMvxViewModel
{
     public CustomMvxAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService)
     {
     }

    protected override void NavigateToFirstViewModel(object hint)
     {
         NavigationService.Navigate<TViewModel>();
     }
}

在App.cs中,替换你的:

RegisterAppStart<FirstViewModel>();

使用:

RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();

这将允许您的第一个Initialize异步。我只确定它适用于Android,并且只有在使用SplashScreen时才能使用。

答案 1 :(得分:1)

我很清楚,这不是与此问题的代码相关的问题,但它与升级到MvvmCross 6.0直接相关。我已经碰到了。

只是添加这个,因为它可能有助于节省几个小时,因为官方文档reg中没有提到这个。到目前为止升级。

因此,就我而言,9.png类中的重载方法存在问题:

Setup

我需要它,因为我的Views和ViewModel位于不同的项目中。升级后,应用程序的运行速度不是初始化,没有任何错误。删除后,一切都开始正常工作。 (显然,最新版本自动处理)。

答案 2 :(得分:0)

为了每个人的利益,Jim创建了bug in MvvmCross GitHub repo。 MvvmCross项目贡献者之一为他的问题和blogged about it提供了一种解决方法。

答案 3 :(得分:0)

除了Jim的帖子,我有一个SplashScreen,我的启动视图模型取决于这是否是第一次激活,关于它的decion是在Core项目的AppStart.Startup()方法中进行的。

我的应用程序现在似乎正在运行,并且在高级别,关键类看起来像这样:

<强> Core.App

public class App : MvxApplication
{           
    public override void Initialize()
    {
        // IoC registrations here

        RegisterAppStart(new AppStart(this));            
    }   
}

<强> Core.AppStart

public class AppStart : MvxAppStart
{
    public AppStart(IMvxApplication application) : base(application)
    {
    }

    protected override async void Startup(object hint = null)
    {
        base.Startup(hint);

        // logic to navigate to intro viewmodel or home viewmodel
    }
}

<强> Droid.Setup

public class Setup : MvxAppCompatSetup<App>
{                
    protected override IMvxApplication CreateApp()
    {
        return new Core.App();
    }

    protected override void InitializeIoC()
    {
        base.InitializeIoC();
        // Custom IoC initialization
    }

    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {            
        return new MvxAppCompatViewPresenter(AndroidViewAssemblies);
    }

    protected override IEnumerable<Assembly> AndroidViewAssemblies => new List<Assembly>(base.AndroidViewAssemblies)
    {
        typeof(NavigationView).Assembly,
        typeof(FloatingActionButton).Assembly,
        typeof(Android.Support.V7.Widget.Toolbar).Assembly,
        typeof(Android.Support.V4.Widget.DrawerLayout).Assembly,
        typeof(Android.Support.V4.View.ViewPager).Assembly,
    };

    protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
    {
        MvxAppCompatSetupHelper.FillTargetFactories(registry);
        base.FillTargetFactories(registry);
    }
}