Android ViewPager不重画内容,保留/变为空白

Android ViewPager不重画内容,保留/变为空白,android,android-viewpager,Android,Android Viewpager,我们这里的ViewPager遇到了一个非常奇怪的问题。我们在每个ViewPager页面上嵌入列表,并在更新列表数据时在列表适配器和ViewPager适配器上触发notifyDataSetChanged 我们观察到的是,有时页面不更新其视图树,即保持空白,有时甚至在分页时消失。当来回翻页几次时,内容会突然重新出现。似乎Android在这里缺少视图更新。我还注意到,在使用hierarchy viewer进行调试时,选择一个视图将始终使其重新出现,这显然是因为hierarchy viewer强制所选视

我们这里的ViewPager遇到了一个非常奇怪的问题。我们在每个ViewPager页面上嵌入列表,并在更新列表数据时在列表适配器和ViewPager适配器上触发notifyDataSetChanged

我们观察到的是,有时页面不更新其视图树,即保持空白,有时甚至在分页时消失。当来回翻页几次时,内容会突然重新出现。似乎Android在这里缺少视图更新。我还注意到,在使用hierarchy viewer进行调试时,选择一个视图将始终使其重新出现,这显然是因为hierarchy viewer强制所选视图重新绘制自身

但我无法通过编程实现这一点;使列表视图无效,甚至使整个视图页面无效,都没有效果

这是与compatibility-v4_r7库兼容的。我还尝试使用最新版本,因为它声称修复了许多与“查看寻呼机”相关的问题,但它让事情变得更糟(例如,手势被破坏了,因此它有时不允许我翻阅所有页面)


是否有其他人也遇到了这些问题,或者您是否知道是什么原因导致了这些问题?

ViewPager尝试在重复使用项目方面做一些巧妙的事情,但它要求您在事情发生变化时返回新的项目位置。尝试将此添加到PagerAdapter:

public int getItemPosition (Object object) { return POSITION_NONE; }

它基本上告诉ViewPager一切都已改变(并强制它重新实例化一切)。这是我脑子里唯一能想到的事情。

Android支持库有一个演示活动,其中包括一个ViewPager,每个页面上都有一个ListView。你可能应该看看它的功能

在Eclipse中(使用Android开发工具r20):

  • 选择
    New>Android示例项目
  • 选择您的目标API级别(我建议使用最新版本)
  • 选择
    Support4Demos
  • 右键单击项目并选择
    Android工具>添加支持库
  • 运行应用程序并选择
    Fragment
    ,然后选择
    Pager

  • 这方面的代码位于
    src/com.example.android.supportv4.app/FragmentPagerSupport.java
    中。祝你好运

    我遇到了这个问题,也遇到了类似的问题。我甚至发现堆栈溢出

    对我来说,在我视图的父视图的父视图中,有人子类化了
    LinearLayout
    并覆盖了
    requestLayout()
    ,而没有调用
    super.requestLayout()
    。这防止了在我的ViewPager上调用
    onMeasure
    onLayout
    (尽管hierarchyviewer手动调用这些)。未经测量,它们将在ViewPager中显示为空白


    因此,请检查您的包含视图。确保它们从视图中生成子类,不要盲目地覆盖requestLayout或任何类似的内容。

    我们终于找到了解决方案。显然,我们的实施遇到了两个问题:

  • 我们的适配器没有删除
    destroyItem()
    中的视图
  • 我们正在缓存视图,以便只需膨胀一次布局,而且,由于我们没有在
    destroyItem()
    中删除视图,因此我们没有将其添加到
    instantiateItem()
    中,而是返回对应于当前位置的缓存视图
  • 我还没有深入查看
    查看页面的源代码
    ——也没有明确说明您必须这样做——但文档中说:

    destroyItem()
    删除给定位置的页面。适配器负责从其容器中删除视图,尽管它只需确保在从finishUpdate(ViewGroup)返回时完成此操作

    以及:

    一个非常简单的PagerAdapter可以选择将页面视图本身用作关键对象,在创建后从InstanceItem(ViewGroup,int)返回它们,并将它们添加到父视图组中。匹配的destroyItem(ViewGroup,int,Object)实现将从父视图组中删除视图,并且isViewFromObject(View,Object)可以实现为返回视图==Object

    因此,我的结论是,
    ViewPager
    依赖其底层适配器在
    instantiateItem()
    /
    destroyItem()
    中显式添加/删除其子项。也就是说,如果适配器是
    PagerAdapter
    的子类,则子类必须实现此逻辑


    旁注:请注意,如果您在
    ViewPager

    中使用列表,我也遇到了完全相同的问题,但实际上我在destroyItem中销毁了视图(我认为)。然而,问题是我使用
    viewPager.removeViewAt(index)销毁了它代替了
    viewPager.removeView((视图)对象)

    mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
    
    错:

    @Override
    public void destroyItem(ViewGroup viewPager, int position, Object object) {
        viewPager.removeViewAt(position);
    }
    
    对:

    @Override
    public void destroyItem(ViewGroup viewPager, int position, Object object) {
        viewPager.removeView((View) object);
    }
    

    也有同样的问题,这与
    列表视图
    有关(因为如果列表为空,我的空视图显示良好)。我刚刚在有问题的
    列表视图上调用了
    requestLayout()
    。现在画得很好

    我也有类似的问题。我缓存视图,因为在
    ViewPager
    中我只需要3个视图。当我向前滑动时,一切正常,但当我开始向后滑动时出现错误,它表示“我的视图已经有父视图”。解决方案是手动删除不需要的项目

    @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int localPos = position % SIZE;
            TouchImageView view;
            if (touchImageViews[localPos] != null) {
                view = touchImageViews[localPos];
            } else {
                view = new TouchImageView(container.getContext());
                view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                touchImageViews[localPos] = view;
            }
            view.setImageDrawable(mDataModel.getPhoto(position));
            Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
            if (view.getParent() == null) {
            ((ViewPager) container).addView(view);
        }
            return view;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object view) {
            //      ((ViewPager) container).removeView((View) view);
            Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
        }
    
    ..................
    
    private static final int SIZE = 3;
    private TouchImageView[] touchImageViews = new TouchImageView[SIZE];
    

    我在使用ViewPager和FragmentStatePagerAdapter时遇到了同样的问题。我尝试使用一个延迟3秒的处理程序来调用invalidate()和requestLayout(),但没有成功。工作原理是按如下方式重置viewPager的背景色:

    MyFragment.java

        private Handler mHandler;
        private Runnable mBugUpdater;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = new ViewPager(getActivity());
            //...Create your adapter and set it here...
    
            mHandler = new Handler();
            mBugUpdater = new Runnable(){
                @Override
                public void run() {
                    mVp.setBackgroundColor(mItem.getBackgroundColor());
                    mHandler = null;
                    mBugUpdater = null;
                }           
            };
            mHandler.postDelayed(mBugUpdater,50);
    
            return rootView;
        }
    
        @Override
        public void onPause() {
            if(mHandler != null){
                //Remove the callback if it hasn't triggered yet
                mHandler.removeCallbacks(mBugUpdater);
                mHandler = null;
                mBugUpdater = null;
            }
            super.onPause();
         }
    

    如果在带有
    FragmentPagerAdapter
    的片段内设置了
    ViewPager
    ,请使用
    getChildFragmentManager()
    而不是
    getSupportFragmentManager()
    作为初始化
    FragmentPagerAdapter
    的参数

    mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
    
    而不是

    mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
    

    对我来说,问题又回到了空调上