Dimezis / BlurView

Dynamic iOS-like blur of underlying Views for Android
Apache License 2.0
3.48k stars 331 forks source link

java.lang.IndexOutOfBoundsException: Index: 3, Size: 0 #191

Closed danmov26 closed 1 year ago

danmov26 commented 1 year ago

Exception java.lang.IndexOutOfBoundsException: Index: 3, Size: 0 at java.util.ArrayList.get (ArrayList.java:437) at android.view.ViewGroup.getAndVerifyPreorderedView (ViewGroup.java:3762) at android.view.ViewGroup.dispatchDraw (ViewGroup.java:4275) at android.view.View.draw (View.java:22221) at android.view.ViewGroup.drawChild (ViewGroup.java:4516) at android.view.ViewGroup.dispatchDraw (ViewGroup.java:4277) at android.view.View.draw (View.java:22353) at eightbitlab.com.blurview.PreDrawBlurController.updateBlur (PreDrawBlurController.java:115) at eightbitlab.com.blurview.PreDrawBlurController$1.onPreDraw (PreDrawBlurController.java:50) at android.view.ViewTreeObserver.dispatchOnPreDraw (ViewTreeObserver.java:1093) at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:3094) at android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1948) at android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:8177) at android.view.Choreographer$CallbackRecord.run (Choreographer.java:972) at android.view.Choreographer.doCallbacks (Choreographer.java:796) at android.view.Choreographer.doFrame (Choreographer.java:731) at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:957) at android.os.Handler.handleCallback (Handler.java:938) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loop (Looper.java:223) at android.app.ActivityThread.main (ActivityThread.java:7664) at java.lang.reflect.Method.invoke (Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:947)

`<eightbitlab.com.blurview.BlurView android:id="@+id/blur_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/view_separator19" android:visibility="gone" app:blurOverlayColor="#991B192E">

    <ViewStub
        android:id="@+id/rl_change_saving"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="@dimen/_20sdp"
        android:layout="@layout/layout_change_saving" />

    <ViewStub
        android:id="@+id/rl_add_income"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginHorizontal="@dimen/_20sdp"
        android:layout="@layout/layout_add_income" />

    <TextView
        android:id="@+id/btn_income_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:layout_marginBottom="@dimen/_27sdp"
        android:drawablePadding="@dimen/_10sdp"
        android:gravity="center"
        android:lines="2"
        android:paddingHorizontal="@dimen/_20sdp"
        android:text="@string/add_income1"
        android:textColor="@android:color/white"
        android:textSize="@dimen/_16ssp"
        android:visibility="gone"
        app:drawableTopCompat="@drawable/ic_add_income" />

    <TextView
        android:id="@+id/btn_change_goal1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginStart="@dimen/_40sdp"
        android:layout_marginBottom="@dimen/_91sdp"
        android:drawablePadding="@dimen/_10sdp"
        android:gravity="center"
        android:lines="2"
        android:paddingHorizontal="@dimen/_5sdp"
        android:text="@string/change_saving1"
        android:textColor="@android:color/white"
        android:textSize="@dimen/_16ssp"
        android:visibility="gone"
        app:drawableTopCompat="@drawable/ic_green_change_accum" />

    <TextView
        android:id="@+id/btn_change_goal2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_marginEnd="@dimen/_40sdp"
        android:layout_marginBottom="@dimen/_91sdp"
        android:drawablePadding="@dimen/_10sdp"
        android:gravity="center"
        android:lines="2"
        android:paddingHorizontal="@dimen/_5sdp"
        android:text="@string/change_saving1"
        android:textColor="@android:color/white"
        android:textSize="@dimen/_16ssp"
        android:visibility="gone"
        app:drawableTopCompat="@drawable/ic_red_change_accum" />

</eightbitlab.com.blurview.BlurView>`

Снимок1

Снимок экрана (819)

Dimezis commented 1 year ago

I had a couple of similar reports, but without steps to reproduce it, I can't help. It crashes somewhere in the ViewGroup, so it's very hard to guess the reason

danmov26 commented 1 year ago

Hello, Dimezis. Thanks for the answer.

Here (https://play.google.com/store/apps/details?id=com.financialaccounting.fincircle) is the application on which google tested on Pixel 5 API 30. There you just need to log in to your account and go to the main screen, where it will be BlurView.

I have never encountered this error myself.

Maybe it's worth trying to paste try catch block at these places ( at eightbitlab.com.blurview.PreDrawBlurController.updateBlur (PreDrawBlurController.java:115) at eightbitlab.com.blurview.PreDrawBlurController$1.onPreDraw (PreDrawBlurController.java:50) ) for now ?

danmov26 commented 1 year ago

Here is the video of this test from Play Console. This happened at 1:08.

https://user-images.githubusercontent.com/66782790/203273311-f5244ab5-a3a4-4d1f-bd27-9b2dcd5e06ff.mp4

danmov26 commented 1 year ago

This is logcat file.

logcat.txt

Dimezis commented 1 year ago

The app is not available for my device, but in any case, it's not very useful without a source code and a reliable way to reproduce this.

danmov26 commented 1 year ago

Good day, Dimezis

I got 4 more errors in the same place

java.lang.IndexOutOfBoundsException: Index: 3, Size: 0
at java.util.ArrayList.get(ArrayList.java:437)
at android.view.ViewGroup.getAndVerifyPreorderedView(ViewGroup.java:3839)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4352)
at android.view.View.draw(View.java:22555)
at android.view.ViewGroup.drawChild(ViewGroup.java:4595)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4354)
at android.view.View.draw(View.java:22701)
at eightbitlab.com.blurview.PreDrawBlurController.updateBlur(PreDrawBlurController.java:115)
at eightbitlab.com.blurview.PreDrawBlurController$1.onPreDraw(PreDrawBlurController.java:50)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1093)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3323)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2135)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8622)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:975)
at android.view.Choreographer.doCallbacks(Choreographer.java:799)
at android.view.Choreographer.doFrame(Choreographer.java:734)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:960)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
at android.app.ActivityThread.main(ActivityThread.java:8057)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)

from Samsung Galaxy A02, Xiaomi Redmi Note 10 Pro, Redmi Note 8 Pro, Galaxy A70. All devices running on Android 11. Снимок экрана (21)

Please, help me. I'll sponsor you, your library is very important to me, I use BlurView in all my apps. But I can't reproduce this issue too, but I'll send you the source code (I use these 2 functions to turn blur on or off in the desired places).

fun BlurView.enableBlur(onWhat: ViewGroup = activity!!.activityLayout) {

    //only for the first time
    if (!clipToOutline) {
        setupWith(onWhat).setFrameClearDrawable(activity!!.window.decorView.background)
        outlineProvider = ViewOutlineProvider.BACKGROUND
        clipToOutline = true
        setBlurEnabled(false)
    }

    visibility = View.VISIBLE
    setBlurRadius(5f)
    setBlurEnabled(true)
}

fun BlurView.disableBlur() {
    setBlurEnabled(false)
    visibility = View.GONE
}

val View.activity: Activity?
    get() {
        var context = context
        while (context is ContextWrapper) {
            if (context is Activity) return context
            context = context.baseContext
        }
        return null
    }

Sorry, I forgot to inform you about installing my app, you need to enable VPN - Great Britain or Russia.

And I'm using your latest library version implementation("com.github.Dimezis:BlurView:version-2.0.3")

danmov26 commented 1 year ago

Another same crash just came, but not from the 11th android, but from the 10th - Galaxy A01 Core. So it repeats not only on the API 30 (Android 11), as I thought earlier.

Dimezis commented 1 year ago

I still can't reproduce it. I also asked some folks from the Google graphics team, but they don't have a concrete answer. Some additional info might help.

1) How frequent is this crash? Do your users experience it once or is it recurring? 2) What is the parent of the BlurView? 3) How do you show this popup with blur? Do you use the BlurView with a Dialog, or do you just switch the visibility of the BlurView?

danmov26 commented 1 year ago

1)

Снимок экрана 2022-12-17 202942

2) RelativeLayout

3) This is how i show the popup (Fragment "Home.kt"): v - this is MainActivity v.b - this is ActivityMainBinding (layout file attached below)

    if (v.dialogBankModule == null) {
        log("Init dialog")
        v.dialogBankBinding = DialogBankModuleBinding.inflate(layoutInflater)
        v.dialogBankModule = v.getDialog(v.dialogBankBinding!!.root, style = R.style.Theme_Dialog)
        v.dialogBankModule!!.window?.let { dialogWindow ->

            dialogWindow.attributes = dialogWindow.attributes.apply { width = v.displayWidth - 40.sdp }

            //click beyond dialog
            v.dialogBankModule!!.setOnShowListener {
                dialogWindow.setFlags(
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                )
                dialogWindow.setFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                )
            }
            dialogWindow.setFlags(
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
            )
        }

        v.dialogBankModule!!.setOnDismissListener {
            v.b.blurView.disableBlur()
            v.b.blurView.updateLayoutParams<RelativeLayout.LayoutParams> {
                addRule(RelativeLayout.ABOVE, R.id.view_separator19)
            }
        }

        v.dialogBankBinding!!.btnCloseBankDialog.onClick { fillCircles() }

        v.dialogBankBinding!!.btnOk1.onClick {
            v.dialogBankModule!!.dismiss()
            v.b.viewstubNotificationSettings.visibility = View.VISIBLE
        }
    }
    v.b.blurView.updateLayoutParams<RelativeLayout.LayoutParams> {
        removeRule(RelativeLayout.ABOVE)
    }
    v.b.blurView.enableBlur()
    v.dialogBankModule!!.show()

Layout:

activity_main.zip

Do you just switch the visibility of the BlurView? - Yes, I guess

Dimezis commented 1 year ago

I have a suspicion it might be related to ViewStub usage, but I'm not able to confirm it. If it's not a big dev effort for you, you might try to replace them with something else, and see if users still experience these crashes.

Also, do you know if this crash occurs after clicking the OK button on that dialog or before? If it's after, what exactly are you doing after closing it? Do you inflate some ViewStubs?

danmov26 commented 1 year ago

What I think. Sorry for my english if there are any mistakes below. I use Google Translate.

The stacktrace references rootView.draw(internalCanvas) in eightbitlab.com.blurview.updateBlur(). rootView is the view that I specify in the setupWith parameter and it is findViewById(android.R.id.content) - which is the highest view in the activity's layout.

In the android.view.View.draw(Canvas) function, each child of the ViewParent must be added to it before anything can be drawn on it, and we see that the number of children of findViewById(android.R.id.content) - 0.

That is, BlurView tries to draw when layout/activity_main has not yet been inflated.

I think ViewStub is not to blame here, because all the crash logs say that the error occurs at the very beginning of starting the activity, after calling onAttachedToWindow(). ViewStubs will inflate later after clicks on other views.

At the moment, I have imported your library as a module in my project and added a check in updateBlur() to see if the rootView has children before calling rootView.draw(internalCanvas).

This is not a solution, of course. just suppression. I need to understand the whole blur mechanism in your library, I will try to solve this error myself, and if anything, I will help you with a solution.

Dimezis commented 1 year ago

and it is findViewById(android.R.id.content) - which is the highest view in the activity's layout.

Ok, but that's not what you posted above in your enableBlur.

That is, BlurView tries to draw when layout/activity_main has not yet been inflated.

That's by definition not possible. If you're accessing the BlurView from the same layout, then everything is inflated. Even if that was somehow the case, having 0 children is a perfectly valid situation and Android framework doesn't crash on it. You also said you're passing the android.R.id.content, which is created regardless of when you inflate your own views.

I think ViewStub is not to blame here, because all the crash logs say that the error occurs at the very beginning of starting the activity, after calling onAttachedToWindow().

The video you posted shows the crash after showing (or hiding) the dialog. Does it crash in a different Activity then?

At the moment, I have imported your library as a module in my project and added a check in updateBlur() to see if the rootView has children before calling rootView.draw(internalCanvas).

That will not work for many reasons. 1) It doesn't matter if the root view has children. It can have no children and it wouldn't crash 2) Checking just the root view is not enough, because getAndVerifyPreorderedView is called in each descendant ViewGroup 3) The problem is that getAndVerifyPreorderedView has some internal inconsistency between preorderedList and childIndex.

If you want to work it around, just try-catch the drawing rootView.draw.

But as I said, I still believe that ViewStub is the culprit here. That's the only thing that's unusual in your setup, and since it removes itself and adds other Views, it's possible that it introduces those inconsistencies

danmov26 commented 1 year ago

OK. Thank you, @Dimezis

I'll try to replace ViewStubs inside BlurViews and surround rootView.draw with try-catch block.

Dimezis commented 1 year ago

Closing due to inactivity