Getting analytics/impression for visible items of RecylerView

I could hardly recall an app without scrollable/recylerView element in design.Often, business intend to seek impressions i.e if user has viewed an item or not. Analytics platform like google/firebase analytics is certainly a best bet for this. However, implementing the same could be a challenging when it comes to recylerview.

Lets try to understand technical challenges :

  1. App performance : App shouldn’t log same events when user is rapidly scrolling back and forth. Remember logging events is actually a network call and sending redundant events would take it toll over user’s network data and might affect app performance (though these events are delivered by play store.)
  2. Log visible items : should log only those events which are fully visible at screen.

Approach to solution :

Step 1 : Find a way to detect actual visible items when user scroll the list.
This can be achieved by addOnScrollListener as shown in below code snippet :

addOnScrollListener(object : OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy:Int) {}

as obvious, whenever user finishes scroll , this onScolled would get invoked and down there we need to put some magical logic to get visible items. Stay connected :)

a) Firstly, get first and last visible item from LayoutManager and,
b) then, iterate from index in difference of last n first visible item.
c) for every index, get the view using (layoutManager as LinearLayoutManager).findViewByPosition(index).
d) Check if,
view.right < width of list . If yes, this view is fully visible
[This is applicable for recyvlerview with layoutManager with orientation horizontal.
For vertical list, check if view.bottom < height]

Step2: Discard visible items as a result of rapid scroll.
we can have some sort of debounce logic to consider only those items that gets visible within certain time (lets say 250 milli seconds ). This also means we would only log items that user has actually viewed/perceived for at-lest 250 milliseconds.

Koltin’s stateFlow or flow can be of great help here. Lets see how.

From step 1, you can emit a flow stream with visible position and you would add debounce() while collecting the flow stream .

If you still here, Lets create a custom recylerView that would emit current visible item using StateFlow.

Tech Lead |Mobile Apps| Trainer | Certified Scrum Master .GitHub : balwinderSingh1989