I have an activity A , and there are 2 fragments associated with this activity, lets us call them F1 and F2. Now there is a fragment switch between these fragments, so in this case is the onResume() activity lifecycle event of activity A called ?
No. Activity's state will not change during a fragment transaction.
Related
I've added a KeyUpHandler to a Button object as follows:
button.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(final KeyUpEvent event1) {
if (event.isDownArrow()) {
counter++;
}
}
});
However, when I debug with SuperDev mode step by step, there are two calls to the onKeyUp where the initial calls has always counter's initial value (0 in this case) and second call has the latest -maintained- value of counter. The method where I added the logic of onKeyUp is also marked as synchronized. I also tried to call removeHandler() method of HandlerRegistration right after onKeyUp is called. The result was that the mentioned two calls happened after first key up event, but when I did another key up event only one more call happened and further key up events area didn't happen. I assume this is sth related with superdev mode or there is some internal overhead after the compilation. What is the correct way of adding any event handlers at GWT? Do we need to always take care of each handler by calling removeHandler() method of HandlerRegistration?
Re: your comment about multiple calls for click/mouseup/keyup
The browser "helps" for the click handler by firing it whenever any event would effectively click, either mousedown, then mouseup but no move, or various touch or keyboard events. Consider calling preventDefault() on an event you have already handled and you don't want the browser to further look at - for example, if you call this on mouseup and keyup, then those particular actions should never result in click events going off.
Can someone give a more detailed explanation about the lifecycle of the default events of a UI5 Control? I know there is this page on the documentation that gives an overview of a Control lifecycle, however, I think it is very brief and wanted something more detailed. Can someone list the order of the events of a Control and explain what every event does?
You are absolutely right. The details of a Control lifecycle and implementation details are very well hidden in the docs. I'll try to sum up my so far understanding for you.
The lifecycle of a Control is mainly determined by:
init : Your little Control is born! Function is called by the framework during constructor execution. Do your initialization stuff here.
onBeforeRendering : Called by the framework before the rendering of the control is started. Triggers before every (re)rendering.
onAfterRendering : Called by the framework after the rendering of the control has completed. Triggers after every (re)rendering.
exit : RIP little Control! Cleans up the element instance before destruction. Called by the framework. Do your clean up here. Btw: If you need to explicitly destruct a Control/Element you should call destroy and not directly exit.
Here is a sample implementation with some sample usages for the different hooks:
sap.ui.core.Control.extend("a.sample.Control", {
init : function() {
// instantiate a sub-control
this._btn = new sap.m.Button();
},
onBeforeRendering : function() {
// deregister a listener via jQuery
this.$("subelement").off("click", this.subElementClick);
},
onAfterRendering : function() {
// register a listener via jQuery on a sub-element
this.$("subelement").on("click", this.subElementClick);
},
subElementClick : function() {
// do stuff
},
exit : function() {
// clean up sub-controls and local references
this._btn.destroy();
delete this._btn;
}
});
Why shouldn't I do my init stuff in my constructor?
There is a basic UI5 constructor in ManagedObject. It "prepares" your UI5 object for you and calls your init function afterwards. That means in your init all settings will already be applied for you and you can access properties and aggregations as usual.
Why shouldn't I call rerender?
The SAPUI5 rendering is intelligent in a sense that it groups and optimizes queued rerenderings. Therefore you should never call rerender directly but instead use invalidate to mark a control for rerendering.
HF
Chris
UI5 provides predefined lifecycle hooks for Controller implementation. You can add event handlers or other functions to the controller and the controller can fire events, for which other controllers or entities can register.
UI5 provides the following lifecycle hooks:
onInit(): Called when a view is instantiated and its controls (if available) have already been created; used to modify the view before it is displayed to bind event handlers and do other one-time initialization
onExit(): Called when the view is destroyed; used to free resources and finalize activities
onAfterRendering(): Called when the view has been rendered and, therefore, its HTML is part of the document; used to do post-rendering manipulations of the HTML. SAPUI5 controls get this hook after being rendered.
onBeforeRendering(): Called every time the View is rendered, before the Renderer is called, and the HTML is placed in the DOM-Tree.
Source: ui5.sap.com/#/topic/121b8e6337d147af9819129e428f1f75
Background:
We have an application using GWT and the GWTP framework providing the MVP architecture. We use GWT's EventBus to broadcast events across presenters.
Requirement:
We have an event called RefreshEvent. The class/presenter firing the event is Parent(P) and the presenter listening to this event is Child(C). We are running into a situation in the application where multiple instances of the C (the listener) are active at the same time in the application. Let's say instance A and instance B of presenter C are active and both are listening for the RefreshEvent. But in a given context in the application I want to selectively fire the event. That is a RefreshEvent fired by P should be received only by instance A of Child C and not by instance B of Child C.
Does GWT provide any mechanism to do this? If not, how can I achieve this.
Our application heavily uses events for inter presenter communication.
Typically, EventBus is used to "broadcast" an event to each party that listens to it (in your example, all instances of your Child C).
If you want a single relationship, your parent can simply call the necessary child:
private Child a;
private Child b;
...
public void on onRefresh() {
/*
* If you need to call child a, call a.doSomething();
* If you need to call child b, call b.doSomething();
*/
}
What is the best practise to update Activity state on Place change? Imagine you have an activity with view that displays list of categories and list of items in the category. If different category is selected then app goes to new place with category ID. I want then to only refresh items and not to create new activity that also re-reads category list.
My current approach is like this:
public class AppActivityMapper implements ActivityMapper {
private ItemListActivity itemListActivity;
...
public Activity getActivity(final Place place) {
final Activity activity;
if (place instanceof ItemListPlace) {
if (itemListActivity == null) {
itemListActivity = new ItemListActivity((ItemListPlace) place, clientFactory);
} else {
itemListActivity.refresh((ItemListPlace) place);
}
activity = itemListActivity;
} else {
itemListActivity = null;
}
...
return activity;
}
...
Alternatives are:
listen to PlaceChangeEvents from within the activity (you can then use a FilteredActivityMapper and CachingActivityMapper for the caching of the activity in your ActivityMapper, so that it's reduced to only create a new activity when asked). †
have some component listen to PlaceChangeEvents and translate them to business-oriented events, the activity then listens to those events rather than PlaceChangeEvents, otherwise the same as above.
decouple the activity from the "screen", make the "screen" a singleton with a reset() method and call that method from the activity's start (possibly passing the category ID as an argument in this case). The "screen" being a singleton could then make sure to load the categories list only once.
in your case, you could also simply put the categories list in a shared cache, so that you don't have to reuse your activity by can create a new one, the categories list will be retrieved once and put in the cache, subsequent activity instances will just use what's in the cache. This is similar to the above, but simpler, and the cache could be used by other parts of the application.
I'd personally rather go with your approach though (with a small exception, see below), as it's the simplest/easiest. Decoupling the activity from the "screen" is also an option; the GWT Team started exploring this approach in the Expenses sample (decoupling the activity responsibility from the presenter responsibility with using MVP) without ever finishing it unfortunately.
Other than that, I don't think any best practice has really emerged for now.
†. I don't like coupling my activities with the places they're used with (I don't quite like the coupling for the goTo calls either, but haven't yet found a clean and simple alternative), so I'd rather not go with this option; and similarly, I'd not pass the place to the activity constructor and refresh method like you did, but rather extract the information out of the place and pass it to the activity (e.g. in your case, only give the category ID to the activity, not the ItemListPlace instance; I would then simply call setCategory in all cases, and not even pass the category ID to the constructor).
In my opinion,
The role of the ActivityMapper is to give you back an Activity from a Place.
The role of the ActivityManager is to start the Activity given back from the ActivityMapper and to stop the current one if different. In your case you would like to "update/refresh" the current Activity.
So I would modify the ActivityMapper so as it will allways give me back the same instance of Activity for a given type of Place. A good way to do so could be to use GIN and use the singleton scope ...in(Singleton.class) to inject your Activity.
If you do that, when changing the url, if the place stays the same (meaning your url has the same word after # and before :) so that the Type of your place stays the same, the ActivityMapper will give you back the same instance of Activity so the ActivityManager will do nothing on the Activity. Check l.126 of ActivityManager
if (currentActivity.equals(nextActivity)) {
return;
}
For me you have 2 options there. The first one, as Thomas said , is to listen to PlaceChangeEvent in your Activity. The new Place you will receive can have new parameters inside based on the new url given and you can "update/refresh" your Activity.
The second one, that I find more in line with the Activity/Place pattern is to modify the ActivityManager so that it calls an update(Place) method on the Activity when the Activity given back by the ActivityMapper is the same that the current Activity.
I haven't tried any of these solutions yet but I will soon ... I might be able to update that post at that time.
You can find more information in this article I wrote on my blog on that topic
Here is a little schema I made to help me understand the pattern, hope it will help :
I would not do any logic in my ActiviyMapper except returning an activity, by creating a new one or giving a previous one (or null). According to me, the mapper doesn't have to know about refresh() or what activities do.
If that, then the logic of 'refresh()' would be given to the activy through the place which holds a token. That token should be holding the information about either what is the state of the request (a new page, reload, an id, etc).
In the activity, first, it asks for the View, the one related to this activity (tip : a singleton given by a 'ClientFactory' is good practice), then it creates a presenter for that view, and bind them together.
Lastly, the activity will use the token from the place to provide any information about state to the presenter. And then, it adds the view in the page.
It's good to know by default, with places and activies, going to the same place doesn't do anything (no reload). But you can take care of it with token and activity-mapper easily.
Hope you'll find an adapted solution for you case. Goodluck.
How can I draw an activity diagram for this use case below?
User opens a closeable window to view a live update of xyz-data.
Specifically, I want to show an object flow in an activity diagram, but the object is an
observable data-storage object (i.e., the GUI control is bound to this data and thus shows a
live view of the data).
It's still an object isn't it? You can either mark it by a special class (i.e. :ObservableDataStorage) or a Stereotype or Keyword (i.e. <<Observable>> : DataStorage). Or/and you can use a relation which is named "observes" between the observer and the observable.