visibilitychange event

507 views
Skip to first unread message

Craig Mitchell

unread,
Aug 7, 2017, 12:33:56 AM8/7/17
to GWT Users
I wanted to know when the visibilitychange event was fired (ie: the browser is minimised).  I've coded it in JavaScript, as I couldn't see it being supported in GWT:

private static native final String getVisibilityState() /*-{
return document.visibilityState;
}-*/;
private static native final void listenForVisibliltyChange(Command onChange) /*-{
document.addEventListener("visibilitychange", function() {
onChange.@com.google.gwt.user.client.Command::execute(*)();
}, false);
}-*/;

I'm not sure if doing calls like this causes memory leaks or anything.  Please shout out if you know of any issues doing it this way.

Thanks.

Jens

unread,
Aug 7, 2017, 5:21:33 AM8/7/17
to GWT Users
Generally ok, given it is a global listener and you probably just install it once on app initialization. However you should use $doc instead of document to make sure you listen on the global document. Depending on your browser support you might want a utility method to check if visibility change events are actually supported by the browser.

static native boolean isSupported() /*-{
  return $doc.hidden !== 'undefined' && $doc.visibilityState !== 'undefined';
}-*/
;

In our app we created a PageVisibilityChangedEvent which extends GwtEvent and then fire it on the app wide EventBus so everyone can easily listen for it. To register the DOM handler we used 

Element doc = Document.get().cast();
DOM
.sinkBitlessEvent(doc, VISIBILITY_CHANGE_EVENT);
DOM
.setEventListener(doc, new EventListener() {
 
@Override
 
public void onBrowserEvent(final Event event) {
   
if (VISIBILITY_CHANGE_EVENT.equals(event.getType())) {
     firePageVisibilityChangedEvent
();
   
}
 
}
});

You could of course also use elemental2 (requires newest GWT) or JsInterop to reduce the amount of JSNI if that is important for you.

-- J.

Craig Mitchell

unread,
Aug 7, 2017, 8:04:27 AM8/7/17
to GWT Users
Thanks Jens.  Now switched it to use $doc.  And, yes, I just register once, and fire a custom event on the event bus.  Although, I just did it using my own event bus like this:

final EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);

listenForVisibilityChange
(new Command() {
 
@Override
 
public void execute() {
   
boolean visible = "visible".equals(getVisibilityState());
    EVENT_BUS
.fireEvent(new WindowVisibilityChangedEvent(visible));
 
}
});


I suspect your way is better, although, I don't really understand what sinking events onto the DOM is doing.

elemental2 looks cool!  Will check it out.

My custom event if anyone wants to reuse it:

public class WindowVisibilityChangedEvent extends GwtEvent<WindowVisibilityChangedEventHandler> {
 
public static Type<WindowVisibilityChangedEventHandler> TYPE = new Type<WindowVisibilityChangedEventHandler>();
 
private boolean visibile;
 
 
public WindowVisibilityChangedEvent(boolean visible) {
   
this.visibile = visible;
 
}
 
 
@Override
 
public Type<WindowVisibilityChangedEventHandler> getAssociatedType() {
   
return TYPE;
 
}

 
@Override
 
protected void dispatch(WindowVisibilityChangedEventHandler handler) {
    handler
.visibilityChanged(this);
 
}
 
 
public boolean isVisibile() {
   
return visibile;
 
}
}


And the handler:
public interface WindowVisibilityChangedEventHandler extends EventHandler {
 
void visibilityChanged(WindowVisibilityChangedEvent windowVisibilityChangedEvent);
}


Cheers.

Thomas Broyer

unread,
Aug 7, 2017, 10:03:59 AM8/7/17
to GWT Users
In addition to $doc vs document, you should wrap your callback with $entry()
Message has been deleted

Craig Mitchell

unread,
Aug 7, 2017, 5:52:20 PM8/7/17
to GWT Users
Thanks Thomas.  Final code for reference:

import com.google.gwt.user.client.Command;

private static native final String getVisibilityState()
/*-{
  return $doc.visibilityState;
}-*/
;

private static native final void listenForVisibilityChange(Command onChange) /*-{
  $doc.addEventListener("visibilitychange", function() {
    $entry(onChange.@com.google.gwt.user.client.Command::execute(*)());
  }, false);
}-*/
;


Thomas Broyer

unread,
Aug 8, 2017, 5:42:53 AM8/8/17
to GWT Users
You're misusing $entry(): it takes a function as argument and returns a function; it should be used to wrap the function(){}.

Craig Mitchell

unread,
Aug 8, 2017, 8:34:58 PM8/8/17
to GWT Users
Ah, yes, good pickup, thanks.  Final, final code:  :-)

import com.google.gwt.user.client.Command;

private static native final String getVisibilityState()/*-{
  return $doc.visibilityState;
}-*/
;

private static native final void listenForVisibilityChange(Command onChange)
/*-{
  $doc.addEventListener("visibilitychange", 
$entry(function() {
    onChange.@com.google.gwt.user.client.Command::execute(*)();
  }), false);
}-*/
;


Reply all
Reply to author
Forward
0 new messages