【问题标题】:Nullpointerexception on dispatchDraw with ViewPager in nested fragment with PageTransformer使用 PageTransformer 在嵌套片段中使用 ViewPager 在 dispatchDraw 上出现 Nullpointerexception
【发布时间】:2014-09-11 22:14:04
【问题描述】:

我正在开发的 Android 应用程序中有一个非常难以描述的错误。我有一个片段,它又包含一个由 FragmentStatePagerAdapter 支持的 ViewPager。寻呼机包含两个片段。

每当我尝试添加 PageTransformer(使用来自 Android 开发者网站的:http://developer.android.com/training/animation/screen-slide.html)时,一切正常,直到我尝试导航离开包含 viewpager(backpress 或常规)的片段。我得到的错误如下。我无法真正追踪是什么导致它 x_x。底部寻呼机构造的代码sn-p。

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

寻呼机构造:

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

我尝试重新排列一些行以防出现某种竞争情况,还尝试反转动画(第 3 行的“假”布尔值),但没有运气。

编辑

经过一些试验和错误,以及 user2152081 的帮助,我采用了一个 hacky 解决方法,用我自己的覆盖 ViewPager 类,并将 draw() 中的 super 调用包装在 try/catch 块中。

@Override
public void draw(Canvas canvas) {
    try {
        super.draw(canvas);
    } catch (NullPointerException e) {
        Log.d("ViewPager", "Nullpointer skipped");
    }
}

【问题讨论】:

  • 感谢@pandanomic 它也解决了我的问题。
  • 如果您将 getChildFragmentManager() 替换为 getActivity.getFragmentManager(),您是否也会遇到同样的问题。如果我使用 getChildFragmentManager(),我遇到了同样的问题,但如果我使用 actvitiy fragmentManager,它就会消失。不知道它是否有帮助,但它解决了我的问题。
  • @JM.Pascal 我确实尝试过,但它会导致其他问题,因为如果我离开并返回该片段,它会尝试重新添加那些查看器片段。嵌套的 viewpager 应该得到 childfragment manager,而不是常规的
  • 我发现如果您在后台添加带有 viewpager 的片段,您需要使用子片段管理器。但是,如果此片段未添加到 backstack(并且使用 retainInstance == false),则可以使用常规。它也让我感到惊讶 ^^ 但我的两种配置都有效。
  • @JM.Pascal 啊,好点。尽管如此,当我尝试这样做时,它仍然对我崩溃(我当时正在使用后台堆栈,尽管我后来确实更改了它,所以我的记忆可能已经关闭)。很高兴你让它工作了,希望能帮助其他看到这个的人。

标签: java android android-fragments android-viewpager


【解决方案1】:

我没有足够的代表发表评论,所以我会在这里回答。

我遇到了完全相同的问题。查看 ViewGroup 的源代码,它通过 android.support.v4.view.ViewPager 的子节点运行并在那里命中 NPE。正如您所说,删除页面转换器有效,为我删除 PagerTabStrip 也是如此。我现在正在查看它,但它看起来像是页面转换器和 PagerTabStrip 之间的某种不兼容。

具体来说,当 ViewPager 被要求重绘自身时,在堆栈跟踪的顶部:

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)

对我来说,此时 ViewPager 只有一个子级 - PagerTabStrip。在 ViewGroup 的 dispatchDraw 中,这是弹出 NPE 的地方:

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);
    }
}

其中 children[] 包含 PagerTabStrip,因为它是第 0 个条目,由于某种原因,children[getChildDrawingOrder(count, i)] 正在评估为 null。

getchildDrawingOrder(count, i) 

在我的实现中没有重载,所以它只返回 i。我无法理解为什么这会被评估为 null - 它似乎应该返回 PagerTabStrip,但事实并非如此,它在尝试访问 children[0] 的成员时会生成 NPE。

我没有适合您的解决方案,但希望这与您遇到的类似。如果你发现了什么,请告诉我。

编辑

不太清楚为什么,但是用这个替换我的 ViewPager 似乎已经解决了崩溃问题:

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;
    }

}

【讨论】:

  • 非常感谢!覆盖 getChildDrawingOrder(...) 为我解决了这个问题!
  • 实际上并没有完全解决问题。只有在 viewpager 中的第二个(最后一个)页面是可点击的,即使我点击了首页,它仍然会记录点击,就像我在第二页上一样。然而,在自定义 viewpager 类中这样做确实解决了所有问题。它很hacky,但它确实有效。我会用它更新我的帖子 @Override public void draw(Canvas canvas) { try { super.draw(canvas); } catch (NullPointerException e) { Log.d("ViewPager", "Nullpointer skipped"); } }
  • 是的,它看起来确实不像它的预期方式,但除了您描述该问题的帖子外,我找不到任何其他内容。似乎没有多少人遇到过。如果您遇到更好的解决方案,请告诉我,因为我现在正在使用此解决方案。
  • 非常感谢你们俩!我已经失去了 2 天的时间来尝试解决这个问题,但多亏了你,它已经解决了 90%。我有 2 个片段,每个片段有 4 个 ViewPager,逻辑和你一样,问题是第一个片段得到了正确渲染的 4 个 ViewPagers,但第二个片段没有。它们存在,但我不知道为什么它们像“隐藏”。我可以“滚动” ViewPagers,但看不到它们。知道为什么吗?覆盖 getChildDrawingOrder 对我有用,但我已经覆盖了平局以防万一......谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
相关资源
最近更新 更多