Unbinding presenters necessary in GWT - java

I'm using the MVP pattern from my GWT application following the example given here http://code.google.com/webtoolkit/doc/latest/tutorial/mvp-architecture.html
I have a single MainPresenter and sub-presenter for each of the panels in the MainView. To show a new sub-presenter, I do something like this:
presenter = new PresenterA(new ViewA(), ....);
presenter.go(panel) // presenter clears the panel and itself to the panel
When PresenterA is created, it binds itself to events in the ViewA. My question is what is the proper way to switch to a new presenter? Right now, I'm simply creating a new presenter and attaching it to the same panel like this:
presenter = new PresenterB(new ViewB(), ....);
presenter.go(panel) // presenter clears the panel and itself to the panel
I have some doubts about this approach. First, am I causing a memory leak when I switch to the new presenter? I've lost both the field that references the old presenter and cleared it from the panel it was attached to. I suppose this means it should be garbage collected, but I'm not really sure. Secondly, what happens to the event bindings that the old presenter had? Will these bindings prevent the presenter from being garbage collected? Do I need unbind them first?
What is the correct way the handle the situation of switching presenters without memory leaks and binding to "dead" events.

I'd suggest that you take a look at the gwt-mvp and/or gwt-presenter libraries, which both take the same approach to this problem. Effectively, you create a base class for all presenters which maintains an internal list of all event registrations that the presenter has. When you then come to switch presenters, you call presenter.unbind() on the old presenter, which then removes all the event handlers you've created.
The base presenter class will look something like this:
public abstract class BasePresenter {
private List<HandlerRegistration> registrations = Lists.newLinkedList();
public void bind() {}
public void unbind() {
for(HandlerRegistration registration : registrations) {
registration.removeHandler();
}
registrations.clear();
}
protected void addHandler(HandlerRegistration registration) {
registrations.add(registration);
}
}
Then in the bind method of your presenter, you pass the HandlerRegistration object's into the addHandler() method:
bind() {
addHandler(foo.addBarHandler(...));
}

Related

How to update UI for callback received while app is in background?

I am creating an android application using MVP architecture. I have created Presenter and Interactor classes. I am struggling to update UI when app is in background and comes back to foreground.
Let's consider following scenario.
Button on UI is clicked and presenter is notified about it. Presenter asked Interactor to provide data from backend. By the time Interactor provides result to presenter somehow UI is in background. How can I save the state of it and change UI components once app is in foreground.
I tried doing following things:
Using flags (turn on the flag and check in onResume to call the method that supposed to be called when callback received. But problem is that let's say if I have 5 different services that can be called by presenter which has different callback then I will require 5 flags which I don't like it)
Using JAVA reflection (Store the name of method be called in HashMap with parameter)
Is there any better way to achieve this?
As name MVP Suggests Model View Presenter
Model : Model is responsible for getter setter methods also known as POJO.
View : Contains activities/fragments with views.
Presenter : Actual Business Logic where you can communicate network calls OR relate with backend databases such as SQLite / MySql.
When button click you need to call presenter which will perform background tasks once it is done you need to notify your view that the response is Success/Failure via CallBacks which done with the help of interfaces.
Example:
interface BaseContract {
interface BaseView {
//Methods for View
void onDoSomething();
}
interface BasePresenter {
void doSomething();
}
}
class BaseMainPresenter implements BaseContract.BasePresenter {
BaseContract.BaseView view;
BaseMainPresenter(BaseContract.BaseView view) {
this.view = view;
}
#Override
public void doSomething() {
if (view != null)
view.onDoSomething();
}
}
class DemoClass implements BaseContract.BaseView {
//Create object of Presenter
/****
* Example :
* BaseMainPresenter baseMainPresenter = new BaseMainPresenter(this);
*/
#Override
public void onDoSomething() {
//Deal with Context here.
}
}
You could add some "pause" logic to your presenter:
Whenever the UI goes to background, you tell the presenter to "pause" and to save any data being received to a cache (could be as simple as a list inside your presenter).
Whenever the UI is back to foreground, you tell your presenter to unpause and to unload its cache to the UI (if the cache list is not null it pushes it to the UI, just like a regular response received by your interactor)

Notifying that value has changed

I'm writing radio player on android. I want to use RDS fucntion and display text in GUI. I have object that manage radio and its functions. When something changes, like RDS text, i want publish it in simple TextBox inside Activity. How i can notify GUI that one of property has changed (and send new value) and i have to refresh that property? Is there any mechanism inside Android that provide such asynchronous notification functionality? I've read about
PropertyChangeListener but this is mechanizm for JavaBeans, can I adopt that? If yes, tell me how i can register and use change listeners in my case.
You can use the Observer Design Pattern
You can use Handler for this job. Here is some examples:
https://developer.android.com/training/multiple-threads/communicate-ui.html
http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers
Cheers
Create a class like this:
abstract class RDSTextListener {
public abstract void onRDSTextChanged(String newText);
}
From your activity do something like:
RDSTextListener listener = new RDSTextListener() {
public void onRDSTextChanged(String newText) {
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView)findViewById(R.id.your_text_view)).setText(newText);
}});
}
}
You will have to pass this listener to your business class. The business class will then call onRDSTextChanged() when its appropriate, and the UI will be updated.
EDIT: Note, this doesn't use interfaces. An abstract class instead. I think that's more Android friendly, avoiding needlessly processing power.

Notifying the presenter that the model has changed

I am using the MVP design pattern and I have registered my presenter as a listener on the various buttons and other interactive elements on my view. And that works fine, I get notified whenever a user performs some action in the GUI.
However I don't the procedure for notifying the presenter when the model changes. I have data coming in from a server that gets processed in, for example, a User model, and changes the value of my User object.
How do you notify the presenter that the model has changed in Java?
Do I let my model hold a reference to the presenter and explicitly call something like presenter.userObjectHasBeenUpdated() in my model after I have altered the User object? Or is there a way of placing a listener on the User object that will automatically call presenter.userObjectHasBeenUpdated() when the User object gets modified?
I would say that you create a dedicated interface like Observer and you let your presenters implement it. Then each presenter can register themselves on the model objects to be notified whenever an object changes.
public interface Observer {
public void update(Object notification, Object source);
}
and in your model:
private List<Observer> observers = new ArrayList<Observer>();
public void addObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected fireNotification(Object notification) {
for(Observer observer:observers) {
observer.update(notification, this);
}
}
Of course you can improve all this by adding Thread-safety, typing your notification etc...
If you are using Swing Components to show the data in view, you can use their respective models for notification. They also work as listeners but have finer levels of notifications depending on component. For example JTable can be notified of change in a row or change in whole table. See http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/table/AbstractTableModel.html#fireTableChanged(javax.swing.event.TableModelEvent) for an example.

GWT MVP. How to use event bus?

In project I use MVP pattern. I have 2 view and 2 corresponding presenters. From "Presenter2" i want to get selected value in "View1". What is the best way to do it? I know that better to use event bus. But so i must to create 2 events and 2 event handlers (1st event will rise when Presenter2 need selected value from View1, and it will be handled in Presenter1. 2nd event will rise in Presenter1 (like: new selectedValueEvent(value) to notificate Presenter2 about selected value. So Presenter2 will handle selectedValueEvent(value) and get value).
If the point when the presenter needs to get the selected value is when the user makes an action you won't get around using an event. (Altough, maybe both presenters could react to the same event so don't need to use two different ones?)
If it is known when the presenter needs to get the value (a defined step in a workflow), you could to it like this:
Keep a reference to the views in the ClientFactory:
public class ClientFactoryImpl implements ClientFactory {
private static final EventBus eventBus = new SimpleEventBus();
/* The views */
private static final SampleView sampleView = new SampleView();
....
public ClientFactoryImpl(){
eventBus.addHandler(ReleaseAddedEvent.type, sampleView);
....
}
// getter and setters
}
So in the Presenter you can get a reference to the view: SampleView view = MyEntryPoint.getClientFactory().getSampleView(); and then you can just call a method from the view which returns the selected value.

Differentiate events for multiple attached gwt widgets

I've been trying to make multiple Presenters "listen" to the same event but I which to make each event unique to the Presenter.
Ex.
I create 3 Composite widgets each in one different tab. They get all attached to the same event at binding. Let's call it the "NewPrescriptionEvent". If this event is fired, all my 3 composites will try to DO the job. I only want one of them to do it.
The only way I found to do this is by creating a temp event id (an integer inside the event) which I check for each widget which is trying to respond to the event.
Code snippet
private class OnNewPrescription implements NewPrescriptionHandler {
#Override
public void onNewPrescription(NewPrescriptionEvent event, int dataObjectId) {
if (getDataObject().getPatientId() == dataObjectId) {
...
}
}
}
During binding I do the usual:
eventBus.addHandler(NewPrescriptionEvent.TYPE, new OnNewPrescription());
The event:
public class NewPrescriptionEvent extends GwtEvent<NewPrescriptionHandler> {
public static final GwtEvent.Type<NewPrescriptionHandler> TYPE = new GwtEvent.Type<NewPrescriptionHandler>();
private int dataObjectId;
public NewPrescriptionEvent(int dataObjectId) {
this.dataObjectId = dataObjectId;
}
#Override
protected void dispatch(NewPrescriptionHandler handler) {
handler.onNewPrescription(this, dataObjectId);
}
#Override
public GwtEvent.Type<NewPrescriptionHandler> getAssociatedType() {
return TYPE;
}
}
I was thinking that the TYPE need to be different each time but still be the same event. Does anyone have a suggestion?
Thx.
Is it the case that you have an arbitrary number of instances of the same presenter and all are listening to the same event type? And each of your presenters 'controls' a different entity an therefore should only react on events coming from that entity? If that's the case the only solution I see is to parametrize the event as you've done.
Sounds like the EventBus probably isn't the best approach here; this is one of the main problems I've personally had with the EventBus: all events are global, and it's hard to differentiate between different events of a given type.
A good set of rules for asynchronous event handling without a shared EventBus is:
Communicate with child widgets via direct method calls.
Communicate with a parent widget via callbacks/handlers/listeners.
Avoid direct knowledge of sibling widgets (probably beside the point here)
So, the widget that contains the 3 tabs can attach callbacks to each tab that, when called, dispatches each event to its appropriate event handler (Presenters, in your case, I believe).
No global communication required, no knowledge of sources or destinations, only one event type, one reusable tab widget type, and the tab class stays simple. In principle, not too different from adding a ValueChangeHandler to a CheckBox (after all, one doesn't subscribe to check box events via the event bus, you just add a handler directly to the widget).
Rough sketch:
public class TabContainer implements IsWidget {
public TabContainer() {
tab1.addNewPrescriptionHandler(
new NewPrescriptionEventHandler() {
#Override
public void handleNewPrescriptionEvent(NewPrescriptionEvent event) {
handleTab1Event(event);
}
});
tab2.addNewPrescriptionHandler(
new NewPrescriptionEventHandler() {
#Override
public void handleNewPrescriptionEvent(NewPrescriptionEvent event) {
handleTab2Event(event);
}
});
...
}
}
And you might even be able to simplify that with some looping and pairing.
Going the other way, this container can also send events back the other way to your widgets from wherever else using the same principles.
Also, depending on what the Event class contains, you might not even need an Event class; you can define your callbacks and params however you want.
I think the title of the question is your answer.
You need different event types for each of the widgets.
You could try using addHandlerToSource(GwtEvent.Type<H> type, Object source, H handler) if you know the source to listen to.
Another possibility would be to extend EventBus to accept some kind of filter on registration.

Categories