Search code examples
androidadmobindexoutofboundsexception

IndexOutOfBoundsException in ViewTreeObserver


Since several months I experience IndexOutOfBoundsExceptions in Crashlytics and Google Play Console. I cannot figure out where exactly it happens, as the stack trace only lists framework code (see stack trace below).

From the firebase events I guess it happens when an ad is shown (it happen always when a level ends and that's where I show ads).

I use AdMob as a mediation network and include AdMob, Unity and Facebook ads. I have plenty of these crashes and it happens on several device types running all kinds of Android versions. As it already happens a long time, I doubt that it has anything to do with API versions, as I already updated them several times since the first occurrence.

Did anyone experience the same issue and was able to solve it?

That's the stacktrace:

java.util.ArrayList.get (ArrayList.java:437)
android.view.ViewTreeObserver$CopyOnWriteArray$Access.get (ViewTreeObserver.java:1267)
android.view.ViewTreeObserver.dispatchOnGlobalLayout (ViewTreeObserver.java:1056)
android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:2823)
android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1857)
android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:8089)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1057)
android.view.Choreographer.doCallbacks (Choreographer.java:875)
android.view.Choreographer.doFrame (Choreographer.java:776)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1042)
android.os.Handler.handleCallback (Handler.java:888)
android.os.Handler.dispatchMessage (Handler.java:100)
android.os.Looper.loop (Looper.java:213)
android.app.ActivityThread.main (ActivityThread.java:8178)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:513)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1101)

These are the APIs my app includes:

implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.core:core:1.5.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.3.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.android.billingclient:billing:4.0.0'
implementation 'com.google.android.gms:play-services-base:17.6.0'
implementation 'com.google.android.gms:play-services-basement:17.6.0'
implementation 'com.google.android.gms:play-services-games:21.0.0'
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'androidx.room:room-runtime:2.3.0'
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
implementation 'com.google.code.gson:gson:2.8.6'
// Monetarization
implementation 'com.google.android.gms:play-services-ads:20.1.0'
implementation 'com.google.android.gms:play-services-ads-identifier:17.0.1'
// Ad mediation
implementation 'com.google.android.ads.consent:consent-library:1.0.8'
implementation 'com.google.ads.mediation:unity:3.6.0.0'
implementation 'com.google.ads.mediation:facebook:6.4.0.0'
// Firebase
implementation 'com.google.firebase:firebase-analytics:19.0.0'
implementation 'com.google.firebase:firebase-ads:20.1.0'
implementation 'com.google.firebase:firebase-core:19.0.0'
implementation 'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.google.firebase:firebase-appindexing:20.0.0'
implementation 'com.google.firebase:firebase-crashlytics:18.0.0'
implementation 'com.google.firebase:firebase-config:21.0.0'
// Dagger
implementation 'com.google.dagger:dagger-android:2.35.1'
implementation 'com.google.dagger:dagger-android-support:2.33'

Solution

  • After days of investigation and adding lots of debug logs to Crashlytics, I finally found the cause of this crash.

    In my case, this was caused by Google Play Games. I had a call to:

    Games.getGamesClient(context, account).setViewForPopups(gameContentView);
    

    which was immediately followed by the showing of a "loading" Dialog, which stayed on screen for about 2 seconds.

    In some rare cases, I guess the addition or removal of an onGlobalLayoutListener performed (asynchronously) by the Games library occurred at the same time than a similar operation triggered by the management of Dialog by Android, which ended up causing the crash.

    Fix: I moved the call to setViewForPopups() to another place where concurrent UI changes are highly unlikely to occur.