-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add abstract layer for displaying elements #3
base: master
Are you sure you want to change the base?
Conversation
Aids porting old code.
*/ | ||
public class WidgetActivityManager extends ActivityManager<IsWidget> { | ||
|
||
private AcceptsOneWidget widgetDisplay; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's never assigned, maybe it doesn't really matter if passing the same display should be a no-op or not (ActivityManager doesn't really care, all it cares about apparently is whether we go from null to non-null, or from non-null to null), but it's a breaking change.
This should be assigned in setDisplay, and tested for non-regression wrt c.g.g.activity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's never assigned, maybe it doesn't really matter if passing the same display should be a no-op or not (ActivityManager doesn't really care, all it cares about apparently is whether we go from null to non-null, or from non-null to null), but it's a breaking change.
Indeed, I didn't see that. I saw it was comparing it (instance compare), so I took the safe route and decided to provide same wrapper for same delegate. If my 2 cents are worth anything, I wouldn't care about instancing new wrapper for each call since it results in much more readable code.
This should be assigned in setDisplay, and tested for non-regression wrt c.g.g.activity.
Yes, that was intention, but I forgot and since ActivityManager
really doesn't care (like you pointed), it didn't matter in tests.
I'll initialize it, but will leave a note for possible simplification (with performance penalty, though).
|
||
private AcceptsOneWidget widgetDisplay; | ||
|
||
private ActivityDisplay<IsWidget> wrapperDisplay; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't it be a local variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, no, at least if we want to return same wrapper for each display. Note that it's initialized inside if
, only if display
is different from previous one. Otherwise, its left as an existing wrapper used in prior call.
*/ | ||
public interface WidgetActivityMapper extends ActivityMapper<IsWidget> { | ||
|
||
WidgetActivity getActivity(Place place); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have an @Override
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.
public interface WidgetActivity extends Activity<IsWidget> { | ||
|
||
default void start(ActivityDisplay<IsWidget> panel, EventBus eventBus) { | ||
start((AcceptsOneWidget) panel::show, eventBus); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because that's what ActivityManager will call, it means the start(AcceptsOneWidget,EventBus)
will receive a different AcceptsOnePanel each time it's started, even if it's actually the same underlying AcceptsOnePanel we passed to the ActivityManager. That panel will have been wrapped twice here: once to convert it to an ActivityDisplay in WidgetActivityManager, and then to converted it back to an AcceptsOneWidget here.
Maybe using an actual wrapper class and testing it here with instanceof would be better?
class AcceptsOneWidgetActivityDisplayWrapper {
final AcceptsOneWidget panel;
AcceptsOneWidgetActivityDisplayWrapper(AcceptsOneWidget panel) {
this.panel = panel;
}
}
AcceptsOneWidget panel;
if (display instanceof AcceptsOneWidgetActivityDisplayWrapper) {
panel = ((AcceptsOneWidgetActivityDisplayWrapper) panel).panel;
} else {
panel = (AcceptsOneWidget) display::show
}
start(panel, eventBus);
Unless we a) those multiple wrappers aren't a problem in practice (in terms of performance and/or code size) and b) don't care about the breaking change (any activity testing either the type of the panel or whether it's the same as in the previous start will break when migrated to this lib)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I said, I would choose simplicity over microoptimization any time, but like you pointed out, this may actually break activities if they compare panels (didn't occur to me they may), so I agree this is safer. Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like activities never had an opportunity to compare panels they got, since ActivityManager
wraps every display/panel with new ProtectedDisplay
every time Activity.start
is invoked (see ActivityManager.tryStart
).
So, (double) wrapping seems inevitable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And on the other hand, that simplifies the code a lot, as setDisplay(AcceptsOnWidget panel)
can then just call setDisplay(panel == null ? null : panel::setWidget)
(i.e. you can remove the widgetDisplay
and wrapperDisplay
)
super(mapper, eventBus); | ||
} | ||
|
||
public void setDisplay(AcceptsOneWidget display) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this extend or wrap?
- by extending, this allows any
ActivityDisplay<IsWidget>
, but breakssetDisplay(null)
that now requires a explicit cast to choose an overload - by wrapping, it cannot be used interchangeably with an
ActivityManager<IsWidget>
(similar to theCompatEventBus
in gwt-event-compat), but ensures backwards compatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like you pointed out, either one is bad. Javadoc could alleviate issue with required cast of null
s, but it's far from optimal. What is your suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would wrap, because I don't see a need for casting to ActivityManager<IsWidget>
. And I would have a constructor that takes the ActivityManager<IsWidget>
to be wrapped, and another constructor that would instantiate one, for ease of use. If one needs both an ActivityManager<IsWidget>
and a WidgetActivityManager
, they could then create the former and wrap it in the latter (similar to CompatEventBus
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapped.
I exposed all public methods from wrapped ActivityManager<IsWidget>
together with wrapped object itself (via (getDelegateManager
) and explained relationship to ActivityManager<IsWidget>
in docs.
Since ActivityManager: a) cares only whether display is null or non-null b) wraps configured display with ProtectedDisplay before it passes it to Activity it's safe to wrap AcceptsOneWidget in new instance of ActivityDisplay on every call to setDisplay.
Don't extend, wrap. Prevents ambiguity when calling setDisplay(null).
Instead of depending on
AcceptsOneWidget
and itsAcceptsOneWidget.setWidget(IsWidget)
mechanism, introduce abstractActivityDisplay<V>
which can be implemented to provide displaying methods for any widgetset.Also, provide two simple
ActivityDisplay
implementations (WidgetActivityDisplay
andElementalActivityDisplay
) for most common scenarios.Specialized test cases are not needed, because
ActivityManagerTest.MyDisplay
is updated to directly implementActivityDisplay<IsWidget>
so this abstraction is already covered by tests.