GWT MVP updating Activity state on Place change
Asked Answered
T

3

6

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;
    }

    ...
Thermomotor answered 22/8, 2012 at 12:26 Comment(0)
V
5

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).

Valediction answered 22/8, 2012 at 13:44 Comment(0)
A
3

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 :

enter image description here

Africander answered 27/2, 2013 at 10:11 Comment(3)
Did you try the second solution? How did it work out or have you found a better way to do this?Nildanile
Sorry not. :( Nerver really had the need for. We simply reload the activity with new params.Africander
Okay. I'm just trying it the was Marting was doing it. I am not sure if that scales but I'm asking it place instanceof MainActivity and if so and not null I just call mainActivity.updateMainContent(place.getCurrentPlaceToken()) in order to update the main content after a click on a button in my menu. It feels like it's quite a lot overhead for just updating the main content but there it is..Nildanile
R
1

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.

Rosenblum answered 23/8, 2012 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.