简体   繁体   中英

Should I use dispatcher.Invoke(…) or ObserveOn(dispatcher)?

I've been given some code to work on where the dispatcher is passed to the view model in its constructor. I'm now wondering if I should use ObserveOn(dispatcher) , or dispatcher.Invoke(...) when I want something to be executed on the UI thread.

For example, I could do this:

this.WhenAny(me => me.SomeValue, _ => Unit.Default)
.ObserveOn(dispatcher)
.Subscribe(_ => SomeMethod());

...

private void SomeMethod()
{
    //do some stuff
}

or I could do this:

this.WhenAny(me => me.SomeValue, _ => Unit.Default)
.Subscribe(_ => SomeMethod());

Which would then mean I could do this instead:

private void SomeMethod()
{
    dispatcher.Invoke(new Action(() =>{//do some stuff});
}

Is there any major difference between the two?

My concern is, what if I want to call SomeMethod() at some other part in the code, which isn't triggered by SomeValue changing? I'd then need to do dispatcher.invoke(new Action(() => someMethod())); , which makes me think using the dispatcher.Invoke(...) inside SomeMethod is the best option.

Is this a good or a bad move? At the minute I'm using both techniques evenly. I intend to shift to one of them, but want to know the right way first.

I would see if I could be given an instance of IScheduler that is an implementation of DispatcherScheduler . This way I would be able to test my code with a TestScheduler without having to get into the bowels of dispatchers and pushing frames etc. Once you have an instance of an IScheduler then you can just use it to ObserveOn(dispatcherScheduler) .

I would also agree with @mclaassen that you should know which scheduler/thread you are on and therefore whether you should need to scheduler/invoke or not. So for example, if you are observing INotifyPropertyChanged events then you will be on the dispatcher so no need to dispatch. If you are receiving a response from a network call or a heavy calculation then you are probably on another thread so you should schedule/dispatch to get back to the dispatcher. The cost of

The standard pattern in Rx for this is to either do no scheduling because you are on the correct thread already:

//this is a ViewModel, and property changes occur on the dispatcher
this.WhenAny(
    vm => vm.PropertyA, 
    vm => vm.PropertyB, 
    _ => Unit.Default)
.Subscribe(_ => SomeMethod());

Alternatively, apply the SubscribeOn / ObserveOn pattern to get off the current thread, perform work and then receive the results on the original thread.

myRepo.GetDataFromNetwork()
    .SubscribeOn(taskPoolScheduler)
    .ObserveOn(dispatcherScheduler)
    .Subscribe(_ => SomeMethod());

Functionally there is no difference. However I would use ObserveOn(dispatcher) and leave SomeMethod() as it is. You might also later be calling SomeMethod() from the UI thread in which case the dispatching would be be unnecessary. I would say it should be the responsibility of the calling code to know whether it is running on the UI thread or not and therefore whether dispatching is required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM