跳至主要内容
← Blog

Detect tab visibility in Java with the webforJ Page API

· 一分钟阅读
Matthew Hawkins
Software Developer

cover image

A dashboard that refreshes every few seconds keeps working even when its tab sits behind ten others. Nobody sees those updates, yet the server still does the work.

To detect tab visibility in Java, webforJ gives you two calls on the Page class: one reads whether the tab is visible right now, and one tells you each time that changes. Both are available from webforJ 26.01. This guide explains what the two states mean, then shows how to pause refresh work while the tab is in the background and resume it when the user comes back.

What the two states mean​

A page is in one of two visibility states, much like the browser's Page Visibility API describes. VISIBLE means the page content is at least partially visible, which in practice is the foreground tab of a window that isn't minimized. HIDDEN covers everything else: a background tab, a minimized window, a locked screen, or a screensaver.

webforJ exposes these as the PageVisibilityState enum. You compare against the constants directly, so the checks in your Java code use the same names as the browser's two states.

Read the state once​

Use getVisibilityState() when you need a single answer, such as when a scheduled task wakes up and wants to know whether it should render anything. The method returns a PendingResult<PageVisibilityState>. The result arrives asynchronously, so you attach your code with thenAccept, and the lambda receives the state when it arrives.

Page.getCurrent().getVisibilityState().thenAccept(state -> {
if (state == PageVisibilityState.VISIBLE) {
// user is looking at the tab
}
});

A common case is a scheduled job that checks the tab before it picks a delivery channel, so it can show an in-app message when the user is looking and a desktop alert when they aren't.

The callback runs once, with the state at the time of the call. It doesn't keep you informed after that. For an ongoing answer, you need a listener.

Listen for changes​

onVisibilityChange(...) registers a listener that fires each time the visibility state changes. addVisibilityChangeListener(...) is the matching method under its full name, so either one works. The listener receives a PageVisibilityChangeEvent, which offers four accessors:

  • getState() returns the new PageVisibilityState.
  • isVisible() returns true when the new state is VISIBLE.
  • isHidden() returns true when the new state is HIDDEN.
  • getPage() returns the Page that produced the event.

The registration call returns a ListenerRegistration<PageVisibilityChangeEvent>. Keep a reference to it, because you need it later to detach the listener.

Use the listener when your work has to follow the tab for as long as the view lives. Use getVisibilityState() when the work only needs the value at one moment. A single view can use both.

Pause updates in a hidden tab​

The usual goal is to stop periodic work while nobody is looking at the page. webforJ's Interval fires an event at a fixed delay in seconds. You call start() to begin, stop() to pause, and restart() to start over.

Pick the delay with the work in mind. A five second refresh suits a status label. A very small delay floods the app with events faster than it can respond to them, and a new delay takes effect only after the interval is stopped and restarted, so call setDelay() before you restart it.

The listener below calls pauseRefresh() when the tab goes to the background and resumeRefresh() when it comes back. Those are your own methods: in a view that refreshes on a timer, one stops the Interval and the other refreshes once, so the user doesn't see stale data, then starts it again.

ListenerRegistration<PageVisibilityChangeEvent> registration =
Page.getCurrent().onVisibilityChange(event -> {
if (event.isHidden()) {
pauseRefresh();
} else {
resumeRefresh();
}
});

A listener only runs when the state changes. If the view can open while its tab is already hidden, combine it with a getVisibilityState() check when the view starts, so the timer only begins while the page is in front.

Clean up when the view closes​

The listener belongs to the page, not to the view. Remove it yourself when the view goes away, or an old view keeps reacting to tab changes after the user has moved on. Keep the registration in a field and call remove() on it in onDidDestroy():

@Override
protected void onDidDestroy() {
if (registration != null) {
registration.remove();
}
}

One detail matters when you choose what to do in each state. HIDDEN also covers a locked screen and a screensaver. Treat it as "the user isn't looking at the page" and pause work that serves the screen. Don't treat it as "the user has left" and throw away state that the user will expect to find when they return.

To try this in a fresh project, create one with startforJ or follow Getting Started. Add the listener to a view on a route, open another tab, and watch your refresh pause and resume. The full API is in the Page Visibility reference, and the feature first shipped in webforJ 26.01.

Frequently asked questions​

Can I detect an inactive browser tab in Java?​

Yes. Call Page.getCurrent().getVisibilityState() to read the current state, or register onVisibilityChange(...) to hear about each change. A tab that isn't in front reports HIDDEN.

How do I pause updates when the tab is hidden?​

Stop your Interval when event.isHidden() returns true, and start it again when event.isVisible() returns true. Remove the listener in onDidDestroy() so it doesn't outlive the view.

Does HIDDEN mean the user has left the app?​

Not necessarily. HIDDEN also covers a minimized window, a locked screen, and a screensaver. Use it to skip background work, not to decide that a session has ended.

正在用 webforJ 构建项目?

与团队聊聊您的项目、迁移事宜,或 webforJ 是否适合您。

联系我们