74

We have found several cases for this kind of crashes reported by backend logging monitoring. It seems the crashes do not tie to particular UX failure. And from the reports, there is no sign of how our own classes being involved(no sign of any of our classes names). Here is an example of typical crashes:

java.lang.NullPointerException: Attempt to read from field 'int android.view.View.mViewFlags' on a null object reference 
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3357) 
at android.view.View.updateDisplayListIfDirty(View.java:14288) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3549) 
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3528) 
at android.view.View.updateDisplayListIfDirty(View.java:14253) 
at android.view.View.getDisplayList(View.java:14315) 
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273) 
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279) 
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318) 
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2561) 
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2377) 
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2007) 
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1086) 
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6453) 
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:846) 
at android.view.Choreographer.doCallbacks(Choreographer.java:647) 
at android.view.Choreographer.doFrame(Choreographer.java:601) 
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:829) 
at android.os.Handler.handleCallback(Handler.java:739) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5254) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:927) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:713) 

Does anyone know whether there is related bug logged against Android code?

M2014
  • 1,094
  • 1
  • 9
  • 16
  • 3
    I want to add that I've been experiencing it when swiping to refresh with a SwipeRefreshLayout and an empty RecyclerView – MathieuMaree Jan 11 '16 at 20:53
  • @MathieuMaree Have you check https://github.com/worker8/TourGuide/pull/34 link? It seems the author found a workaround in his case - who knows, maybe it will help you too – Konstantin Loginov Jan 12 '16 at 08:42
  • 2
    please provide code which could be used to reproduce this crash – gio Jan 16 '16 at 10:02

11 Answers11

30

Possible Solution

I had this same issue. I setup an animation and in onAnimationEnd I was removing the object that had been animated which is when problems started. What I did was setup an asynchronous Runnable to wait 100 milliseconds after the animation had stopped before removing the animated object:

the object previously animated is this._loader

private void removeLoader() {
    final ContentContainer self = this; // "CustomContainer" needs to match the type of `this`
    Handler h = new Handler();
    h.postAtTime(new Runnable() {
        @Override
        public void run() {
            MainActivity.instance.runOnUiThread(new Runnable() { 
                @Override
                public void run() {
                    try {
                        if(self._loader == null) {
                            // there is no loader. quit now while you still have the chance!!
                            return;
                        }
                        while(self._loader.getParent() != null) {
                            removeView(self._loader);
                        }
                    } catch(Exception e) {
                        Crashlytics.logException(e);
                        e.printStackTrace();
                    }

                    self._loader = null;
                }
            });
        }
    }, 100);
}

Cheers

Jacksonkr
  • 31,583
  • 39
  • 180
  • 284
  • @DeanWild It's a total hack, I agree. I'm sure there is a tread-safe / correct way in doing this but I dare say the time & creativity needed for a "proper" solution outweighs the benefits of a quick hack, but I've been wrong before... – Jacksonkr Mar 11 '16 at 18:01
  • 2
    @Jacksonkr Thanks for the answer. In my case simply putting the `removeView` call in a `runnable` that is `post`ed on the same view the `removeView` is called on fixed the issue. That feels like a "more proper" solution as there is no delay involved. – Daniel F Mar 08 '17 at 08:40
  • Are you skipping the `runOnUiThread` ? Depending on the setup that may get a person into hot water. – Jacksonkr Mar 08 '17 at 14:16
  • 1
    By using `postAtTime()` what you are unintentionally doing, is never invoking the runnable. I'm sure you meant `postDelayed()` instead, but the fact that this resolved your problem leads me to believe this isn't a resolution at all; you're effectively keeping the views in memory. This really isn't a solution for use cases such as animating views in a RecyclerView. – Paul Lammertsma Oct 22 '18 at 12:13
18

I was facing same problem. I resolved with Handler.

new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                   // remove fragment from here
                }
            });
Pawan Chaurasiya
  • 881
  • 2
  • 16
  • 30
  • Very not obvious from the error message, but in my case it was removing the view in the AnimationListener. posting it to get back to main thread solved the problem. – David Berry Mar 31 '20 at 19:39
17

The problem is in the ViewGroup's dispatchDraw() method. This method tries to draw all the ViewGroup's children. When a child is null, you get an exception, which most likely comes from this line: if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { (notice the mViewFlags).

So the problem is that one of your views, somewhere, is not properly initialized. I'm afraid that's the best I can do.

kevinpelgrims
  • 2,148
  • 1
  • 18
  • 29
4

We started getting this error unexpectedly too. It was tracked down to fragment animations being the issue. More specifically using custom animations with replace() in a fragment transaction when the app is built against Local Maven repository for Support Libraries rev > 26.

Possible solution

Downgrade Local Maven repository for Support Libraries to rev 26. See here

veritas1
  • 8,740
  • 6
  • 27
  • 37
2

Possible cause: I was having the exact same issue. It turned out it started to happen when I added code to modify the view tree within onDraw() call. To be specific, I removed a view with children in my derived onDraw() when certain conditions were met. I now believe this is a bad thing to do, probably because the platform is trying to draw views that I have now removed from the view tree. I resolved the issue by posting the deletion with Runnable to happen after the call to onDraw() has finished.

Teemu Lätti
  • 121
  • 1
  • 5
1

This is mainly because you are removing a view duaring touchEvent dispatching. It's hard to find out the who is removing the view in a large code base.

For those who want the crash analysis, can check this post:

https://medium.com/@wanxiao1994/crash-analysis-resetcancelnextupflag-nullpointerexception-e409b7bdbad

Shaw
  • 1,445
  • 16
  • 21
0

Override dispatchDraw method and put in it a try/catch block, like this:

public void dispatchDraw(Canvas c)
    {
        try
        {
            super.dispatchDraw(c);
            return;

        }
        catch(Exception exception)
        {
            return;
        }
    }
0

While it is ugly and not good practice, the only thing I could get to reliably work is just catching the exception in dispatchDraw() like below:

override fun dispatchDraw(canvas: Canvas?) {
        /*
         * We're doing this because of the below exception that is out of our control:
         * java.lang.NullPointerException: Attempt to read from field
         * 'int android.view.View.mViewFlags' on a null object reference at
         * android.view.ViewGroup.dispatchDraw(ViewGroup.java:4111)
         */
        try {
            super.dispatchDraw(canvas)
        } catch (e: NullPointerException) {

        }
    }

Just make sure your desired behavior is working correctly and you're not breaking something else by doing this. Again, not ideal, but it's the only thing I could get to work and I'm absolutely sure in my case it's not breaking anything else.

Peace to you :)

Bassam Helal
  • 380
  • 3
  • 12
0

I was trying to navigate from Fragment A to Fragment B, and Fragment A was a form that required data from Fragment B.

So when I tried to navigate without filling up A, it was throwing this exception.

Also, even if A was independent of the data B, it was throwing this exception.

I have no idea why but I added a condition where the user had to fill-up the form before navigating away and that solved the issue.

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
Anirudh Ganesh
  • 446
  • 4
  • 22
0

It's a threading issue. Could be that you're refreshing your ViewPager or some other adapter.

Have been facing this issue on and off, and realised that if you place it in the UI Thread in your Activity, then it'll render just fine.

activity?.runOnUiThread{
   // Add Your UI Updating Methods Here
}
Morgan Koh
  • 2,297
  • 24
  • 24
0

No delay / threading stuff required. Plz Read through... The post is old but for the future readers, it would be helpful. I explain in details what really happens with a use-case I faced and solved.

I have a viewflipper which animates flipping next and previous through its children using simple slide-in / slide-out animations. I need to remove a view from viewflipper just after flipping is completed and to make sure it happens at the right time, slide-in animations have a listener where I remove the view in there. Everything worked perfect for flip-to-next while flip-to-previous threw the above mentioned exception. After some trial and error turns out:

when flipping to next the following is the sequence:

1-slide-out starts
2-slide-in starts
3-slide-out finishes
4-slide-in finishes

So having listener on slide-in is the right thing since both animations are guaranteed to be completed there.

But when flipping to previous the following is the sequence:

1-slide-in starts
2-slide-out starts
3-slide-in finishes
4-slide-out finishes

As you can see, when slide-in finishes, slide-out is not done yet and hence there happens the exception. I simply set the listener on slide-out and it worked perfectly.

While all of the other answers urge to remove the view with a delay (which of course helps to make sure concurrent animations are all done) but as you could see that is not the case.

As a general rule, when you have a set of animations running on a view (even with the exact same durations) -although the general belief is that they would finish both together - but they won't (remember that threads are virtually concurrent).

Masoud Dadashi
  • 1,044
  • 10
  • 11