How to implement MVP in JavaFX - java

Before some time, i started looking for a pattern to decouple UI from a logic of my app. I decided to use MVP, but there is one significant problem which i cant solve.
How can i inject a instance of presenter into view, if classes that implements Application, are launched from static method. There is also no choice to launch specific instance of class implementing Application, so parameters in constructor are useless.
Also i do not use FXML, my view class is coded in java.
PS: Sorry for my english, as it's not my native language

You can pass a reference from say Main.java to a Presenter. In Main do this:
Presenter p = new Presenter(); // This is your Presenter class
p.setReference(this); // Call a method in the presenter
// and here is a method in Main.java just as an example
public StackPane getRootView(){
return this.rootView;
}
Then in Presenter you have:
private Main main;
public void setReference (Main main) {
this.main = main;
}
Your presenter can now call methods in Main e.g.
StackPane sp = main.getRootView();
You could also do this in the constructor of Presenter.

I have written a sample code to answer to this problematic.
https://github.com/oterrien/JavaFX_Presenter.git
The view interface provides the intention of the view.
For example:
getting and setting text
getting and setting result1
getting and setting result2
getting and setting event handler for the Add button
The concret view is created from FXML file. Each field of the control is defined with #FXML. The action to be triggered when the button is clicked is also a method and is prefixed by #FXML.
The concret view implements the interface by providing a mapping between #FXML fields and getting/setting methods. And the triggered method does just call the event handler.
The concret view is also responsible of creating the presenter (which refers itself as view).
That is the important point. The presenter acts upon the model and the view. It retrieves data from repositories (the model), and formats it for display in the view.
For that purpose, the presenter should be able to call the view in order to set data and retrieve data once updated by user. That is why, the presenter contains a reference of the view. But it should also provide action to be done when view's event handlers are called.
When a user clicks on button "Add", the method which is bound with FXML is called. This method call the EventHandler which has been set by the presenter. In other words, the presenter is responsible of registering its own method to the view's EventHandler.
Finally, testing the presenter just consists in creating a mock of the view.

Related

Are actions allowed in MVVM? Android

If MVVM is all about data binding and cannot do something like view.doThis(), otherwise it's MVP, then how to invoke actions on views?
Suppose I have view that has a snackbar. View is controlled by its ViewModel. How is this ViewModel supposed to show snackbar without going snackbar.show()?
In MVVM, ViewModel captures the state of the view. View observes the ViewModel for changes and updates itself. Thus, the communication between View & ViewModel happens through change of values (as against method calls in MVP).
Since Snackbar is like a global behaviour (like Toast), it can be implemented at the Activity/Fragment level. So, you can make a MessageHelper interface and pass it to the ViewModel as a dependency. Activity will implement it and display Snackbar.
Example:
ItemViewModel that consumes the interface
Activity base class that implements the interface
However, its possible that there is some view specific behaviour which cannot be implemented at the Activity level. For such cases, you can make use of databinding.Observable to trigger an event. For example, lets say we want to animate a particular view. We can create a BindingAdapter
#BindingAdapter({"shakeTrigger"})
public static void showSnackbar(View view, Void trigger) {
// Do the animation here. You could add meaningful argument types to control the animation
}
In XML, we can apply this using
<TextView
bind:shakeTrigger="#{vm.shakeTrigger}"/>
Then, in the viewModel, you can trigger the shake using Data Binding apis. One way using BaseObservable can be:
public class ConfigurationViewModel extends BaseObservable implements ViewModel {
#Bindable
public final Void shakeTrigger = null;
public void shake() {
notifyPropertyChanged(BR.shakeTrigger);
}
}
If you use RxJava, the trigger could be implemented from rx.Observable. You can checkout my library to use RxJava with Data Binding.
https://github.com/manas-chaudhari/android-mvvm
The short answer is you don't and that's actually a good thing. In MVVM ViewModel is responsible for preparing and storing data for the view. So it gets the data from the model and makes it ready to be set on the view but it doesn't set the value, Setting the value and updating view states are responsibilities of the view itself, View in MVVM watches for changes in data and updates itself.
An example of this would be showing an empty list page when your list is empty. To do this in MVVM, you define a state for the view visibility in your ViewModel lets call it emptyPageVisibility and then update this value appropriately.
public class PlaylistDetailViewModel extends ViewModel {
private MutableLiveData<Integer> emptyPageVisibility = new MutableLiveData<>();
private void someMethodInYourViewModel(){
emptyPageVisibility.setValue(View.VISIBLE);
}
}
Then inside your view, you observe this and update the view when this data is changed like this
viewModel.getEmptyPageVisibility().observe(this,
visibility -> emptyPageView.setVisibility(visibility));

Detecting events inside a class [duplicate]

I have a custom View class that extends Spinner. I'm trying to figure out what the correct way to talk to the Activity that it's embedded in is, when the user makes a selection. I see that the OnItemSelected listener gets a reference to the Adapter, but I'm not clear on whether or not I should be using this adapter and walking up its parent chain somehow, or if I should just talk directly to the context (for some reason that doesn't feel safe, even though I can't think of a way in which it might fail, offhand).
the right way to do that, is to "listen" to your custom view by exposing an interface which your view holding a reference to instance of him, and you hosting activity should implement. exactly like the OnItemSelected interface and any events which android views are exposing is been implemented. this is the observer design pattern.
for example:
public class MyCustomSpinner extends Spinner {
public MyCustomSpinner(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public interface IMyEventListener {
public void onEventOccurred();
}
private IMyEventListener mEventListener;
public void setEventListener(IMyEventListener mEventListener) {
this.mEventListener = mEventListener;
}
protected void someMethodWhichDoingSomthingAndShouldRaiseAlsoTheEvent() {
/*
* Some Code which the function doing //more code...
*/
if (mEventListener != null) {
mEventListener.onEventOccurred();
}
}
}
this is how you will use it from your activity:
mMyCustomSpinner.setEventListener(new IMyEventListener() {
#Override
public void onEventOccurred() {
// TODO Auto-generated method stub
}
});
I'm trying to figure out what the correct way to talk to the Activity that it's embedded in is, when the user makes a selection.
You don't want to "talk to the Activity that it's embedded in". You want to talk to the controller responsible for the View. Today, that might be an Activity. Tomorrow, that might be a Fragment.
I see that the OnItemSelected listener gets a reference to the Adapter, but I'm not clear on whether or not I should be using this adapter and walking up its parent chain somehow
That implies that the View knows the specific type of Adapter, since the Adapter interface does not have any sort of getContext() method. Moreover, it ties you to talking to the Activity, which is not a good plan at this point, as mentioned above.
Personally, I'm a bit dubious about having a custom Spinner subclass in the first place. But, assuming there's a good reason for it, you should follow Tal Kanel's advice (posted while I was writing this) and design a custom listener interface for this custom event that is being declared by your custom View. Have the controller (Activity or Fragment) supply an implementation of that interface -- this could be directly implemented on the controller, or implemented as an anonymous inner class (as in Tal Kanel's answer), etc. Have your custom View call method(s) on the listener interface as needed.
The correct way is using a listener of some sort. I think you can make direct reference, your code would just not be reusable for another project then...
A simple solution -
((ParentClass) context).functionToRun();
Where ParentClass is the class name of the activity.

Java: View (GUI) and Controllers Interaction with MVC?

How does one most efficiently connect a view and a controller in a MVC-esque Java application. Currently, I'm doing the following:
Controller creates view and passes itself into the view as a parameter:
MyView view = new MyView(this);
View has ActionListeners for buttons. ActionListener doesn't do much but fire an action in the controller:
private class ButtonAListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent arg0) {
controller.clickedButtonA();
}
}
It is working OK, but is this acceptable? For example, if a button is clicked in the view, the ActionListener passes that information into the controller, which does some calculations, and passes back a command to update the view.
IMHO it is acceptable. I think any solution is ok, as long as no tight coupling occurs. Depending what GUI library you are using (AWT,SWT, Swing..) different classes are appropriate though. Btw. you should check adapters out (if you dont know them already): http://blogs.oracle.com/CoreJavaTechTips/entry/listeners_vs_adapters
I'd recommend moving the creation of view from the controller. If view and controller are to separated (and that's the whole point), the controller should only have a setter method (or other dependency injection mechanisms). I think you should have a launcher class that creates the controller and views and then connects them together.

Java View to Controller Observer

I need help. I am struggling to get my Observers working in java. Can someone explain to me using MODEL-VIEW-CONTROLLER Architecture how to create and observer from View To Controller.
This is because if i press a button on the view the action event has to call notify the controller of that button being pressed.
For that I'm implementing observers to minimize class coupling.
I have a class Controller, View (Swing using JFrame), and an Application Class that holds the main method.
I tried implementing it so that Controller implements Observer and the View extends Observable.
After triggering the event of clicking the button all code except the notifyObservers("OBJECT") gets called. It disappears somewhere in the java library.
Any Help Will be much appreciated.
the model should extend observable and the view should implement observer (you want the view to depend on the model). you will need to call setChanged to after you change the state of the model to force the observers to be notified.
Double check, that your controller is really observing/listening to the (correct) button instance. Use a debugger and set some breakpoints to check whether notifyObservers is called and who is receiving the notification.

Decoupling View from Controller in Java MVC Pattern

First time posting a question on StackOverflow, so please go easy on me :)
From what I understand, proper use of the model-view-controller pattern requires that we decouple the view and controller such that the view knows nothing about the controller. I'm having a bit of a problem understanding how to do this using Java Swing.
Say I have a view (some class that would extend JFrame), and this view has a button. Is it safe to say that I would want to register the controller as an ActionListener of the button? Or do I make it a listener of the entire view itself.
And how do I go about doing this without doing something like:
button.addActionListener(myController)
in the view, because if I were to do this in the view code, wouldn't it now have a dependency on the controller?
I didn't post any code because, frankly I don't have much to go on at the moment.
any help is appreicated!
It might help to not think of the view in terms of buttons etc. so much as an interface. The interface makes it possible for web ui's, command line consoles, etc. to be written and fulfill the role of the view.
In the case of your button event, the button represents a call to some command carried out by the controller.
So, you could have an interface like this:
public interface MyViewIf {
// used by the controller to register its self as a listener of the view
public addViewListener(ViewListener vl);
...
}
and:
public interface ViewListenerIf {
// used by the View to notify any listeners of control events etc.
public onViewEvent(ViewEvent ve);
}
Then your controller would implement ViewListenerIf and register it's self with a factory generated instance of MyViewIf. That way the controller doesnt need to know any specifics about your view class(es).
Your view class would then internally handle it's own button events, turn them into ViewEvent objects and call onViewEvent() on the controller that registered it's self with the view, leaving the View 100% oblivious to the existence of the Controller.
Make an actionlistener in your view class. From your actionlistener you call your controller.
Code for actionlistener:
controller.doButtonClick();
This means you need to inject your model and controller to the view. That is how I do it.
Take a look at the Spring Framework to get an insight in implementing the MVC pattern.
Brief Spring tutorial Tutorial

Categories