来自错误线程的MvvmCross Realm访问

时间:2018-07-16 12:51:48

标签: xamarin.android realm mvvmcross viewmodel

例外

  

MainViewModel中错误线程的领域访问

申请流程

SplashScreen> MainActivity(Exception)

[Activity(MainLauncher = true
        , Icon = "@mipmap/ic_launcher"
        , Theme = "@style/Theme.Splash"
        , NoHistory = true
        , ScreenOrientation = ScreenOrientation.Portrait)]
    public class SplashScreen : MvxSplashScreenActivity
    {
        public SplashScreen()
            : base(Resource.Layout.SplashScreen)
        {
        }
    }

MainActivity

public class MainActivity : MvxAppCompatActivity<MainViewModel>,ViewPager.IOnPageChangeListener,View.IOnTouchListener
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.activity_tutorial);

            if (ViewModel.IsCompletedOrNot) 
                ViewModel.OpenMainViewModel.Execute();
         }

MainViewModel

     [AddINotifyPropertyChangedInterface]
    public class MainViewModel : MvxViewModel
    {
        private Realm _realm;

        private bool isCompleted = false;

        public TutorialViewModel(IMvxNavigationService navigationService)
        {
            _realm = Mvx.Resolve<Realm>();
        }


    public bool IsCompletedOrNot{                   
                get
                {                                     
                    if (_realm.All<IsFirstTimeAppStartUpRealm>().Count() > 0)
                    {
                        isCompleted=true;

                    }else{

                        isCompleted = false;
                    }

                    return isCompleted;
                }
            }
}

App.CS

           var key = ConfigManager.Settings?.DatabaseEcryption?.EncryptionKey;
            if (key != null && key.Length > 0)
            {
                config.EncryptionKey = key;
            }
            Mvx.RegisterSingleton<Realm>(() => Realm.GetInstance(config));

            Realm _realm = Mvx.Resolve<Realm>();
            int count = _realm.All<IsFirstTimeAppStartUpRealm>().Count();



            //RegisterCustomAppStart<CustomAppStart>();

            // App start
            if (count>0)
            {
                RegisterNavigationServiceAppStart<MainViewModel>(); 
            }
            else
            {
                RegisterNavigationServiceAppStart<OtherViewModel>();
            }

下面的行引发异常。

_realm.All<IsFirstTimeAppStartUpRealm>().Count() > 0

通过SplashScreen进入应用程序时,它始终会崩溃,并且如果从MainActivity启动,则可以正常运行。

2 个答案:

答案 0 :(得分:1)

MvvmCross不保证App启动在UI线程上运行。我很可能会在ThreadPool线程上运行。

为了将一段代码封送到主线程,您可以解析IMvxMainThreadAsyncDispatcher(> = 6.1.x)或IMvxMainThreadDispatcher并请求Action在主线程上运行主线程:

var dispatcher = Mvx.Resolve<IMvxMainThreadAsyncDispatcher>();
int count;
await dispatcher.ExecuteOnMainThreadAsync(() => 
{
    count = _realm.All<IsFirstTimeAppStartUpRealm>().Count();
});

答案 1 :(得分:0)

我有一种相当不错的方法,可以从应用程序中删除这些代码异味。我最近才开始使用Realm(到目前为止已喜欢它),但是我一直使用ReactiveProperty通知我的视图层VM更改-真的很好。

https://github.com/runceel/ReactiveProperty

ReactiveProperty是.NET的Rx框架,它将您的属性包装在一个实例中,该实例会根据需要生成INotifyPropertyChanged事件。您可以将所有这些属性链接在一起,因为它们彼此依赖,并且事件会在整个属性中传播。属性更改后,您将不再具有这些“通知此,通知该”的长列表。 相反,您在代码的单个部分(通常是构造函数)中声明所有成员如何相互依赖

因此,您可以将链的根放置在Realm线程上,所有相关的通知都将发布在该线程上。

所以,我的ViewModel看起来像这样(伪代码):

class VM
{
  public ReactiveProperty<AppStartInfo> Entity { get; set; }
  public ReactiveProperty<bool> IsFirstLaunch { get; set; }

  public VM(){
    var syncCtx = SynchronizationContext.Current;
    Entity = new ReactiveProperty<AppStartInfo>();

    // this property will fire its notifications on the syncCtx.
    // remember to bind your view to "IsFirstLaunch.Value"
    IsFirstLaunch = Entity.SubscribeOn(syncCtx).Select(x => x.IsFirstLaunch).ToReactiveProperty()
  }

  public async Task Init()
  {
    // let's get our realm instance on to the syncCtx.
    syncCtx.Post(() => {
        Entity.Value = Realm.Find(typeof(AppStartInfo), 0); // or whatever you need.
    });
  }
}