Skip to content
Manuel Mauky edited this page Jun 16, 2016 · 3 revisions

Notifications

de.saxsys.mvvmfx.utils.notifications

This package provides an observer mechanism that you can use to send notifications which are identified by a string throught all of the application. You can pass objects with an notification.

#####Use the notification mechanism to notify the View from a ViewModel####

Sometimes you want to trigger something in the View from the ViewModel. For this reason the ViewModel Interface offers two Default Methods, which can be used to communicate from the ViewModel to the View using internally the NotificationCenter.

ViewModel#publish and ViewModel#subscribe

public class MyViewModel implements ViewModel {
    public void someAction() {
	publish(PersonLoginViewModelNotifications.OK.getId(), PersonLoginViewModelNotifications.OK.getMessage());
    }
}

public class MyView implements FxmlView<ViewModel> {

    @InjectViewModel viewModel;
    
    viewModel.subscribe(PersonLoginViewModelNotifications.OK.getId(), (key, payload) -> {
			String message = (String) payload[0];
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setTitle(message);
			alert.setContentText(message);
			alert.show();
    });
}

#####Listen globally for a notification####

@Inject
private NotificationCenter notificationCenter;

[...]

notificationCenter.subscribe("someNotification",
			new NotificationObserver() {
			
			@Override
			public void receivedNotification(String key, Object... objects) {
				System.out.println("Received Notification: "+ key + "With object count:" +objects.length);
			}
		}
	);
Send a notification
@Inject
private NotificationCenter notificationCenter;

[...]

notificationCenter.publish("someNotification");

notificationCenter.publish("someNotification","arg1",new CustomArgTwo());

Testing Notifications

When notifications are send with the ViewModel.publish method, we are delivering the notification on the JavaFX Application thread to make the handling in the View easier. While this is generally a good approach it can make testing harder because in a JUnit test there is no FX thread. To make testing easy again we are checking if there is a FX thread available to send the notification. This is the case at runtime but not when a JUnit test is executed. When no FX thread is present the notification will be send directly on the same thread that is currently running (the JUnit thead in this case). This way it's easy to subscribe to the message in the unit test and make the needed assertions.

The downside of this approach is that the handling in the unit test differs slightly from the handling at runtime. In most cases this won't be a problem but maybe in some it is. To be able to test the handling of notifications in a more "realistic" way, i.e. sending and receiving notifications on the FX thread like it is done at runtime, we have included a utility called "NotificationTestHelper". The test helper implements the NotificationObserver interface and can be used to subscribe to notifications. It will record all received notifications and can be used for assertions afterwards:

public class MyViewModel implements ViewModel {
    public static final String ACTION_KEY = "my-action";

    public void someAction() {
        ...
        publish(ACTION_KEY);
    }
}

// unit test
@Test
public void testSomething() {
    // given
    MyViewModel viewModel = new MyViewModel();
   
    NotificationTestHelper helper = new NotificationTestHelper();
    viewModel.subscribe(MyViewModel.ACTION_KEY, helper);
  
    // when
    viewModel.someAction();
 
    // then
    assertEquals(1, helper.numberOfReceivedNotifications());
}

The NotificationTestHelper takes care for the handling of the JavaFX Application Thread. The numberOfReceivedNotifications method is a blocking operation that will wait for other actions on the UI-Thread (like the publishing of notifications).

Additionally you can use the NotificationTestHelper to test notifications send from other threads as well. In this case you will need to provide a timeout (in milliseconds) as constructor parameter. The test helper will wait for the given amout of millis until it checks how many notifications where received.