Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullpointerexception on dispatchDraw with ViewPager in nested fragment with PageTransformer

I'm having a pretty nondescript bug in the Android app I'm working on. I have a fragment, which in turns contains a ViewPager that's backed by a FragmentStatePagerAdapter. The pager contains two fragments.

Whenever I try to add a PageTransformer (using the ones from the Android developer site: http://developer.android.com/training/animation/screen-slide.html), everything works fine until I try to navigate away from the fragment containing the viewpager (backpress or regular). The error I get is the following. I can't really trace what's causing it x_x. Code snippet of the pager construction at the bottom.

Process: edu.utcs.android, PID: 11728
    java.lang.NullPointerException
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2946)
            at android.view.View.draw(View.java:14476)
            at android.support.v4.view.ViewPager.draw(ViewPager.java:2171)
            at android.view.View.getDisplayList(View.java:13370)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.draw(View.java:14476)
            at android.widget.FrameLayout.draw(FrameLayout.java:472)
            at android.view.View.getDisplayList(View.java:13370)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.getDisplayList(View.java:13365)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2959)
            at android.view.View.getDisplayList(View.java:13365)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.support.v4.widget.DrawerLayout.drawChild(DrawerLayout.java:870)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.getDisplayList(View.java:13365)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.getDisplayList(View.java:13365)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.draw(View.java:14476)
            at com.android.internal.widget.ActionBarOverlayLayout.draw(ActionBarOverlayLayout.java:381)
            at android.view.View.getDisplayList(View.java:13370)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.View.draw(View.java:14190)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3103)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940)
            at android.view.View.draw(View.java:14476)
            at android.widget.FrameLayout.draw(FrameLayout.java:472)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2324)
            at android.view.View.getDisplayList(View.java:13370)
            at android.view.View.getDisplayList(View.java:13412)
            at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1577)
            at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1449)
            at android.view.ViewRootImpl.draw(ViewRootImpl.java:2410)
            at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2282)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1912)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1022)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5708)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
            at android.view.Choreographer.doCallbacks(Choreographer.java:562)
            at android.view.Choreographer.doFrame(Choreographer.java:532)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5083)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
            at de.robv.andro

Pager construction:

mAdapter = new LabPagerAdapter(getChildFragmentManager());
        mPager.setAdapter(mAdapter);
        mPager.setPageTransformer(false, new ZoomOutPageTransformer());
        mPager.setCurrentItem(mLabPosition);

I've tried rearranging some lines in case it was some sort of race condition, and also tried reversing the animation (the "false" boolean on the 3rd line), but no luck.

EDIT

With some trial and error, and some help from user2152081, I've gone with a hacky workaround by overriding the ViewPager class with my own, and wrapping the super call in draw() in a try/catch block.

@Override
public void draw(Canvas canvas) {
    try {
        super.draw(canvas);
    } catch (NullPointerException e) {
        Log.d("ViewPager", "Nullpointer skipped");
    }
}
like image 267
Zac Sweers Avatar asked Apr 13 '14 01:04

Zac Sweers


1 Answers

I don't have enough rep to comment, so I'll answer here.

I ran into exactly the same issue. Looking at the source for ViewGroup, it was running through the children of the android.support.v4.view.ViewPager and hitting the NPE there. As you stated, removing the page transformer worked, as did removing the PagerTabStrip for me. I'm looking at it right now, but it looks like some kind of incompatibility between the page transformer and the PagerTabStrip.

Specifically, when the ViewPager is asked to redraw itself, at the top of your stack trace:

at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2946)
at android.view.View.draw(View.java:14476)
at android.support.v4.view.ViewPager.draw(ViewPager.java:2171)

For me, at this point the ViewPager has only a single child - the PagerTabStrip. In dispatchDraw in ViewGroup, this is where the NPE pops up:

for (int i = 0; i < count; i++) {
    final View child = children[getChildDrawingOrder(count, i)];
    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
        more |= drawChild(canvas, child, drawingTime);
    }
}

Where children[] contains the PagerTabStrip as it's 0th entry, for some reason, children[getChildDrawingOrder(count, i)] is evaluating to null.

getchildDrawingOrder(count, i) 

is not overloaded in my implementation, so it just returns i. Its beyond me as to why this is evaluating to null - it certainly seems like it should return the PagerTabStrip, but it's not and it's generating the NPE when trying to access the children[0]'s members.

I have no solution for you, but hopefully this is similar to what you've run into. Let me know if you find out anything.

EDIT

Not quite sure why, but replacing my ViewPager with this seems to have resolved the crash:

package ca.test;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;

public class TestViewPager extends ViewPager {

    public TestViewPager(Context context) {
        super(context);
    }

    public TestViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        return i;
    }

}
like image 92
user2152081 Avatar answered Oct 17 '22 06:10

user2152081