1

I'd like to be able to know when the user can actually see the content in my widget/fragment (versus just know that the widget was rendered below the fold or in a fragment that is cached but might never actually get shown).

I've searched high and low for some kind of hook that lets you know when something is displayed to the screen, but can't find one. Does such a thing exist, or is this something that Android overlooked? Is it possible to patch this together in some way, or am I just out of luck?

Thanks!

Todd O'Bryan
  • 2,234
  • 17
  • 30
  • What about using a Toast from that widget/fragment? – learner Mar 30 '16 at 17:50
  • Are you looking to find out if an individual `View` in your layout is visible to the user? If so, this answer might help you: http://stackoverflow.com/a/12428208/3962091 – NoChinDeluxe Mar 30 '16 at 18:00
  • @NoChinDeluxe, The problem with that is it tells you *if* a view is visible, but not *when* it becomes visible. Do we have to result to constantly checking to find out when it happens? Shouldn't Android have an event for this? – Todd O'Bryan Mar 30 '16 at 23:56
  • I'm curious as to what your context for this question is now. There are several callbacks that notify you when a Fragment is attached, created, resumed, visible, etc. If those aren't enough, then there's a possibility that your design is not ideal or flat out flawed. In my experience, when you are bucking up against the system this much and can't seem to find a shred of documentation, it usually means YOU are the one doing something wrong. That's how it's been with me, anyway. – NoChinDeluxe Mar 31 '16 at 14:32
  • I want to do impression tracking. In other words, I want to know what users have seen at the finest granularity I can. – Todd O'Bryan Mar 31 '16 at 17:43

1 Answers1

0

From the docs of the Activity class:

The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().

The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods you can maintain resources that are needed to show the activity to the user. For example, you can register a BroadcastReceiver in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user no longer sees what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity becomes visible and hidden to the user.

The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). During this time the activity is in front of all other activities and interacting with the user. An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep, when an activity result is delivered, when a new intent is delivered -- so the code in these methods should be fairly lightweight.

The second and third points seem to clearly mention what you're looking for (the onResume() method). If you're using fragments, the same rules apply. The onResume() method of the fragment will be called after onResume() of the activity.

http://developer.android.com/reference/android/app/Activity.html http://developer.android.com/reference/android/app/Fragment.html#Lifecycle

EDIT :
Well, apparently there is no direct solution to this. I have an idea, but it's more of an improvisation than a proper solution. Also, it may or may not work. Try these things -

  1. If you're using fragments in a ViewPager (with tabs), the FragmentPagerAdapter will call setUserVisibilityHint(true) on the currently displayed fragment. You can check for this with getUserVisibilityHint() in your fragment.
  2. If you're using a ScrollView as a container, maybe you could listen for scroll changes and determine whether your fragment is visible or scrolled out. See this answer for more info.
  3. For individual widgets, you can check for visibility with View.isVisible().

None of these options provide a definite event-based mechanism to check for visibility, but maybe you can use them somehow. One way would be to define your own callbacks, and override the above methods to call them. Let me know if you get any of these methods (or some other method) to work.

Community
  • 1
  • 1
Rohan
  • 1,180
  • 2
  • 15
  • 28
  • This only says when the fragment is in the foreground. It still might not be on the visible screen, but might be down below the fold. On some (large) devices it might be visible to the user. On others it might not be. – Todd O'Bryan Mar 30 '16 at 21:35
  • @TOB What you are saying happens when `onStart()` is called. When `onResume()` is called, the activity is "in front of all other activities and interacting with the user." That does mean it's contents are visible to the user. Read the doc I quoted once again. – Rohan Mar 31 '16 at 05:20
  • Can't there be two fragments one above the other, with the lower one off the screen, but reachable via scrolling? If not, I'm really asking about widgets. – Todd O'Bryan Mar 31 '16 at 17:45
  • 1
    I'm going to accept this answer, because it clarifies that an event-based solution doesn't exist, and gives pointers to possible solutions. If anyone comes up with anything, please post back here! – Todd O'Bryan Apr 04 '16 at 19:18