Codementor Events

Android Detect To See If Fragment is Visible to User.

Published Oct 02, 2017

Kotlin is here!

Imagine that you have one activity and several fragments inside it, which you dynamically add and remove using FragmentManager.

A few days ago in my project, I realized that I couldn't understand which fragment is currently visible to the user.

I need this because when the app receives notifications from the server, I don’t want to update fragments that are not visible now
because it consumes processor time and the UI will be less responsive.

I want updates for only currently visible fragments.

I need a method that indicates that a fragment has become visible/invisible to the user (like Activity.onPause(), Activity.onResume()), APIs that I need to handle notifications in a good way, like in this example.

I had a problem though. I can’t find method onBecomesVisible() in Fragment API. I thought that onPause() and onResume() would be triggered, but I realized that they’re connected with Activity lifecycle.

So if Activity wasn’t paused/resumed -> this method won’t be called 😦

First, I tried to find solutions in standard Fragment API. I had four fragments in stack one above another, and method Fragment.isVisible and Fragment.getUserVisibilityHint() returned true for all of them. Funny story 😃

My solution is to use one method for navigation and execute Fragment.setUserVisiblityHint(boolean) every time a fragment’s
visibility has changed. It looks like the following:
example one.

The client code looks like the following:
example two.

As you can see, the main difference between this and the usual method is that I manually call from.userVisibleHint = false to mark that the fragment is not visible to the user. Now I know which fragments are not visible to the user.

Another problem is to detect when the fragment is visible to the user. The easiest solution was to add code to.userVisibleHint = true to the previous method, but we will not cover cases when the user clicks the back button (popBackStack() executes).

To handle this case, we need to listen to back stack changes and every time it’s changed, get the current fragment and execute fragment.userVisibleHint = true
Code: example here.

I must say, there are some bugs where onBackStackChangedListener is executed twice on support lib version 25.0.1.

Update to 25.4.0 version and all will be all right.

Finally, we can replace our func onBecomesVisible() with func setUserVisibleHint(). Example here.

Of course, to prevent destroyed fragments, and to opt out of receiving notifications, we must unsubscribe from them in method onDetach().

And finally, I don’t like to call this every time, but there is not enough functionality for the library, so I just place all of this logic in class NavigationDelegate.If you find this useful, you can use this code here.

Usage in client code here.

Sample of code at github.

Discover and read more posts from Алексей Мисюля
get started