Skip to content

[NavigationView] Insets listener set on NavigationView header can be called many times per second in an infinite loop #5040

@equeim

Description

@equeim

Description:

If an insets listener is set on NavigationView's header, it is possible to get into a situation when it will start to be called many times per second in an infinite loop. This happens on Android < 11.

Expected behavior: Insets listener is not called hundreds of times per second.

Minimal sample app repro:

navigation-view-bug.zip

Launch the app. Open the left drawer. Click on "request insets" button. Observe counter going up (the counter shows the number of times insets listener was called).

Android API version: 29

Material Library version: 1.13.0

Device: Any Android 10 device

I believe that the cause of the issue is the combination of two factors:

  1. ScrimInsetsFrameLayout (which NavigationView extends) calls its onInsetsChanged method with insets before consumeSystemWindowInsets():

These insets are applied directly to the header container in NavigationMenuPresenter:

ViewCompat.dispatchApplyWindowInsets(headerLayout, insets);

However when ScrimInsetsFrameLayout's insets listener return insets after consumeSystemWindowInsets(), these insets (which are now different) are then also applied to the header through ViewGroup's insets dispatching.

  1. Now the piece that actually causes the loop is in the ViewCompat.setOnApplyWindowInsetsListener(): https://github.com/androidx/androidx/blob/d0264c461cc7e0eee8003ef0d1de0d5ee496a0d0/core/core/src/main/java/androidx/core/view/ViewCompat.java#L5051

What happens is that when insets are applied again (because of requestApplyInsets() or some other reason), insets from ScrimInsetsFrameLayout.onInsetsChanged and from ViewGroup dispatching arrive in pairs and because they are different (the equals() check fails) it causes wrappedUserListener to repeatedly call requestApplyInsets() which created a self-sustaining loop.

I'm not sure why it doesn't happen immediately on application start though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions