【问题标题】:ViewPager Fragments getting destroyed over time?ViewPager 片段随着时间的推移而被破坏?
【发布时间】:2012-04-09 02:07:30
【问题描述】:

我正在使用Android的support.v4包来开发一个包含多个Fragments的ViewPager。

我试图在用户更改页面时隐藏视图。因此,我实现了一个OnPageChangeListener 来监听我的适配器,并在发生页面更改时在我的Fragments 中调用update() 方法。但是我收到了NullPointerException,我不知道为什么。

代码如下:

public class MyActivity extends FragmentActivity implements
        OnPageChangeListener {

    private static final int NUM_ITEMS = 2;
    private ViewPager mPager;
    private static SpaceAdapter mAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_pager);

        mAdapter = new SpaceAdapter(getSupportFragmentManager());
        mPager = (ViewPager) findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

        mPager.setOnPageChangeListener(this);
}

    public static class SpaceAdapter extends FragmentPagerAdapter {

        public SpaceAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case 0:
            return new MyFragment();
            case 1:
            return new MyFragment();
            default:
            return new MyFragment();
            }
        }
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
        Log.i("pagination", "scroll state changed: " + arg0);
}

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        // Log.i("pagination", "page scroll: " + arg0 + " with: " + arg1 + ", " + arg2);
        if (mAdapter.getItem(arg0) instanceof IUpdateOnPage) {
            ((IUpdateOnPage) mAdapter.getItem(arg0)).updateOnPage();
        }
    }

    @Override
    public void onPageSelected(int arg0) {
        Log.i("pagination", "page selected: " + arg0);
    }
}

public class MyFragment extends Fragment implements
        SurfaceHolder.Callback, IUpdateOnPage {

    private SurfaceView charts;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.crew, null);
        bindViews(v);
        return v;
    }

    private void bindViews(View v) {
        charts = (SurfaceView) v.findViewById(R.id.civ_charts);

        charts.getHolder().addCallback(this);
        Log.i("wtf", "huh " + String.valueOf(charts == null)); // logs false
    }

    @Override
    public void updateOnPage() {
        if (charts != null) {
            Log.i("crew surface", "hidden");
            charts.setVisibility(View.GONE);
        } else {
            Log.i("crew surface", "charts is null");  //THIS HERE gets logged
        }
    }
}

w当我复制/粘贴时,我删除了 SurfaceHolder.Callback 方法,但它们在那里。 bindViews(v) 方法记录 charts == null,并且总是返回 false。当我页面时,updateOnPage 被调用,charts == null 返回 true。为什么会发生这种情况,我该如何解决?

这是第 108 行:

charts.setVisibility(View.GONE);

【问题讨论】:

  • 好的,经过进一步调查,我假设片段在分页开始时被破坏(即使视图仍然存在?)。滑动时,我仍然可以看到“一半”片段,直到新片段捕捉到全视图。所以,如果所有的引用都被收集了,剩下的就是视图,我该怎么做呢?
  • 如果您收到NullPointerException,您可以发布 logcat 输出吗?
  • 好吧,我实际上正在捕捉它,因此不会引发异常。问题是charts.setVisibility(View.GONE);。图表为空。它位于第二个代码示例的最后,位于else 的正上方。添加了堆栈跟踪。

标签: java android nullpointerexception android-fragments android-viewpager


【解决方案1】:

初始化ViewPager时添加以下内容,

mPager.setOffscreenPageLimit(NUM_ITEMS-1);

在您的情况下,这会将屏幕外页面的数量设置为 1(即,当另一个页面当前处于焦点时,它将在内存中保留额外的屏幕外页面)。这将强制您的 ViewPager 保留所有 Fragments,即使它们不在焦点上。

【讨论】:

  • 解决了我遇到的另一个小性能问题,非常感谢!但是当这个片段使用相同的空指针显示时它仍然会崩溃..
  • 实际上,这解决了核心问题。我不再需要调用 setVisibilty(View.gone) 了。奇怪,但谢谢!澄清一下——SurfaceView 没有正确分页,即使我滑动它,它仍然保留在所有页面上。
  • 这很奇怪,因为 setOffscreenPageLimit 在 v4 中默认为 1(并且 NUM_ITEMS - 1 等于 1),但我很高兴您的问题已得到解决。
  • 实际上我将代码“笨拙”了一点,然后将其粘贴到此处。我有 7 个片段,但这是唯一一个有表面视图的片段,也是唯一一个有问题的片段......不过谢谢!
  • 很高兴听到您成功了。在我看来,ViewPager 的生命周期没有得到很好的记录......这可能有点棘手。
【解决方案2】:

我检查了您的代码,我认为问题在于在onPageScrolled 中,您正在调用getItem。这个实现(实际上就像它在 web 上的大多数实现一样)每次都返回一个新实例。但是,我见过的大多数示例都不会调用getItem,所以这通常没问题。

在您的情况下,我会在 getItem 中懒惰地创建片段:如果该位置不存在,则创建它,然后将其挂在 ArrayList 或其他集合中,但如果它已经存在,只需从该集合中返回它。

否则,你创建一个片段实例 A,然后滚动到另一个片段实例 B。你试图告诉片段实例 A 清理一些视图,但你最终告诉一个新的片段实例 C 这样做。它还没有机会建立自己的视图,所以你得到了指向图表的空指针。

【讨论】:

  • 哦,这很好。我从某处的谷歌示例中获得了这个实现,但我将研究实现一个数组或其他东西来维护片段。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
相关资源
最近更新 更多