1

我最近升级到在 Windows 上运行的 Xamarin Studio。我有一个简单的 mvvmcross TipCalculator 教程实现,它在 Android 和各种 Windows 版本上运行良好。升级后,Android 应用程序开始在 Main 活动中抛出 NullReferenceExceptions(如下):

[Activity(Label = "TipCalculator.Android", MainLauncher = true, Icon = "@drawable/icon")]
public class TipCalculatorActivity : MvxBindingActivityView<TipCalculatorViewModel>

{
    protected override void OnViewModelSet()
    {
        SetContentView(Resource.Layout.TipView);//Throws NullReferenceException
    }

}

在对 mvvmcross 代码做了一些挖掘之后,我在 MvxAndroidViewsContainer 类中找到了这个方法:

public virtual IMvxViewModel Load(Intent intent, Type viewModelTypeHint)
{
    if (intent == null)
    {
        // TODO - some trace here would be nice...
        return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
        //return null;
    }

    if (intent.Action == Intent.ActionMain)
    {
        // TODO - some trace here would be nice...
        return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
    }

    if (intent.Extras == null)
    {
        // TODO - some trace here would be nice...
        return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
        //return null;
    }

    IMvxViewModel mvxViewModel;
    if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
        return mvxViewModel;

    return CreateViewModelFromIntent(intent);
}

在原始代码中,有两种情况会返回 null。在其中的每一个中,我都将其替换为对 Activator.CreateInstance() 的调用。

我不确定原始实现背后的基本原理是什么,我有点担心我破坏了一些东西。任何人都可以解释为什么这种方法会返回 null 以及我是否破坏了 mvvmcross 中的一些基本内容?

4

1 回答 1

1

我不知道您当前的问题与新的 Xamarin 工具有什么关系。您对 NullReferenceExceptions、更改的文件和博客文章的描述让我迷失了……

我猜想你的开发设置和你的应用程序中可能有很多事情发生了变化。如果您可以一次退一步,那么您将能够弄清楚关键的变化是什么。

听起来您的代码更改可能会解决您当前的问题 - 但它绝对是在问题(无论它是什么)发生后应用的补丁,所以这不是我现在想要在核心代码中做的事情。


就您询问的代码而言:

        if (intent == null)
        {
            // TODO - some trace here would be nice...
            return null;
        }

只有在没有 Intent 的情况下以某种方式创建了 Activity 时才会发生第一个 null - 我猜这不会发生?(除非在您当前的工具设置中的某个地方,这可能被设置为空?)


        if (intent.Action == Intent.ActionMain)
        {
            // TODO - some trace here would be nice...
            return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
        }

这是直接启动活动的正常路径 - 此活动将没有用于构造 ViewModel 的额外参数。

通常这条路径不会发生在许多 MvvmCross 应用程序中 - 大多数应用程序通过启动屏幕活动启动。


        if (intent.Extras == null)
        {
            // TODO - some trace here would be nice...
            return null;
        }

对于任何其他活动,Mvx 应该在 Extras 中插入了一些特殊的 ViewModel 信息——所以 Extras 不可能为空......如果发生这种情况,那么创建活动的代码是什么?


IMvxViewModel mvxViewModel;
if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
    return mvxViewModel;

return CreateViewModelFromIntent(intent);

这是已导航到的活动的正常启动路径。


如果有帮助,这里是最新的 v3 代码 - 添加了一些跟踪(但也增加了 savedState 的混乱 - 现在忽略这个!):

    public virtual IMvxViewModel Load(Intent intent, IMvxSavedState savedState, Type viewModelTypeHint)
    {
        if (intent == null)
        {
            MvxTrace.Trace(MvxTraceLevel.Error, "Null Intent seen when creating ViewModel");
            return null;
        }

        if (intent.Action == Intent.ActionMain)
        {
            MvxTrace.Trace("Creating ViewModel for ActionMain");
            return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
        }

        if (intent.Extras == null)
        {
            MvxTrace.Trace(MvxTraceLevel.Error, "Null Extras seen on Intent when creating ViewModel - this should not happen - have you tried to navigate to an MvvmCross View directly?");
            return null;
        }

        IMvxViewModel mvxViewModel;
        if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
        {
            MvxTrace.Trace("Embedded ViewModel used");
            return mvxViewModel;
        }

        MvxTrace.Trace("Loading new ViewModel from Intent with Extras");
        return CreateViewModelFromIntent(intent, savedState);
    }
于 2013-03-06T15:56:15.597 回答