【问题标题】:IllegalStateException: The application's PagerAdapter changed the adapter's content without calling PagerAdapter#notifyDataSetChangedIllegalStateException:应用程序的 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged
【发布时间】:2014-04-08 17:02:59
【问题描述】:

我正在使用ViewPager 示例,其中ActionBar 选项卡取自Android 文档here

不幸的是,当我调用addTab 方法时,应用程序崩溃并出现以下异常:

IllegalStateException:应用程序的 PagerAdapter 更改了 适配器的内容而不调用 PagerAdapter#notifyDataSetChanged! 预期适配器项计数 0,找到 1。

这是FragmentPagerAdapter 代码:

public static class TabsAdapter extends FragmentPagerAdapter
            implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

        static final class TabInfo {
            private final Class<?> clss;
            private final Bundle args;

            TabInfo(Class<?> _class, Bundle _args) {
                clss = _class;
                args = _args;
            }
        }

        public TabsAdapter(Activity activity, ViewPager pager) {
            super(activity.getFragmentManager());
            mContext = activity;
            mActionBar = activity.getActionBar();
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);
        }

        public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
            TabInfo info = new TabInfo(clss, args);
            tab.setTag(info);
            tab.setTabListener(this);
            mTabs.add(info);
            mActionBar.addTab(tab);
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mTabs.size();
        }

        @Override
        public Fragment getItem(int position) {
            TabInfo info = mTabs.get(position);
            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            mActionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            Object tag = tab.getTag();
            for (int i=0; i<mTabs.size(); i++) {
                if (mTabs.get(i) == tag) {
                    mViewPager.setCurrentItem(i);
                }
            }
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
        }
    }
}

我没有在我的代码的任何其他部分修改我的适配器,我正在从主线程调用addTab 方法,addTab 方法以对notifyDataSetChanged 的调用结束。正如文档建议的那样:

PagerAdapter 支持数据集更改。数据集更改必须发生在 主线程并且必须以调用 notifyDataSetChanged() 结束 类似于从 BaseAdapter 派生的 AdapterView 适配器。

【问题讨论】:

    标签: android android-viewpager illegalstateexception fragmentpageradapter


    【解决方案1】:

    我很难让我的ViewPager 正常工作。最后,好像是文档中的例子是错误的。

    addTab 方法应该如下:

    public void addTab(Tab tab, Class<?> clss, Bundle args) {
            TabInfo info = new TabInfo(clss, args);
            tab.setTag(info);
            tab.setTabListener(this);
            mTabs.add(info);
            notifyDataSetChanged();
            mActionBar.addTab(tab);
        }
    

    注意最后三个操作的顺序。在原始示例中,notifyDataSetChangedmActionBar.addTab 函数之后调用。

    不幸的是,只要您在ActionBar 上调用addTab,您添加的第一个选项卡就会被自动选中。因此,onTabSelected 事件被触发,并在尝试检索页面时抛出 IllegalStateException,因为它注意到预期项目数与实际项目数之间存在差异。

    【讨论】:

    • 我一直在寻找这个。我是唯一一个觉得奇怪的是错误读起来好像我没有调用 notifyDataSetChanged(),而我真的需要在 notifyDataSetChanged() 之后执行操作(在我的情况下为 setCurrentItem)?
    【解决方案2】:

    我通过在下次调用 getCount() 之前调用 notifyDataSetChanged() 来修复它:

    private boolean doNotifyDataSetChangedOnce = false;
    
    @Override
    public int getCount() {
    
      if (doNotifyDataSetChangedOnce) {
        doNotifyDataSetChangedOnce = false;
        notifyDataSetChanged();
      }
    
      return actionBar.getTabCount();
    
    }
    
    private void addTab(String text) {
    
      doNotifyDataSetChangedOnce = true;
    
      Tab tab = actionBar.newTab();
      tab.setText(text);
      tab.setTabListener(this);
      actionBar.addTab(tab);
    
    }
    
    private void removeTab(int position) {
    
      doNotifyDataSetChangedOnce = true;
    
      actionBar.removeTabAt(position);
    
    }
    

    【讨论】:

      【解决方案3】:

      通过引用 getCount() 中的选项卡,我遇到了和你一样的错误:

      @Override
          public int getCount() {
              return mTabs.size();
          }
      

      当实例化时,它应该作为一个单独的变量传入,或者应该在集合被填充/变异之后设置寻呼机。

      【讨论】:

        【解决方案4】:

        试试这个。我工作过

        protected void onPostExecute(Void aVoid) {
                    super.onPostExecute(aVoid);
                    System.out.println("Asyncrona onPostExecute");
                    /*::::::::::::::::::: Guardo los cambios  ::::::::::::::*/
                    //menuTabs = menuTabs2;
                    viewPager = (ViewPager) rootView.findViewById(R.id.viewPager_menu);
                    costumAdapter = new CostumAdapter2(getActivity().getSupportFragmentManager());
                    costumAdapter.notifyDataSetChanged();
        
                    viewPager.setAdapter(costumAdapter);
                    tabLayout = (TabLayout) rootView.findViewById(R.id.tablayout_menu);
                    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                        @Override
                        public void onTabSelected(TabLayout.Tab tab) {
                            System.out.println(" La Seleccionado: " + tab.getText()+", POSICION: "+tab.getPosition());
                            viewPager.setCurrentItem(tab.getPosition());
                        }
        
                        @Override
                        public void onTabUnselected(TabLayout.Tab tab) {
                            viewPager.setCurrentItem(tab.getPosition());
                        }
        
                        @Override
                        public void onTabReselected(TabLayout.Tab tab) {
                            viewPager.setCurrentItem(tab.getPosition());
                        }
        
                    });
                    viewPager.setAdapter(costumAdapter);
                    tabLayout.setupWithViewPager(viewPager);
                    loading.closeMessage();
        
                }
        

        【讨论】:

          【解决方案5】:

          我的问题并不完全相同,但上下文相似。

          我有一个 AlertDialog 显示在具有 ViewPager 并且正在使用 AppCompatActivity 的布局中。旋转屏幕时出现 IllegalStateException 并崩溃。

          感谢@almisoft 和@Zagorax 的回答,我在显示对话框之前尝试致电notifyDataSetChanged();,问题似乎已经消失。

          【讨论】:

            【解决方案6】:

            我在FragmentStatePager 适配器中遇到了同样的问题。在onResume() 重新初始化adpater 和ViewPager 时,将显示相同的错误IllegalStateException。解决办法:

            添加标签addtab时,通过设置setSelected参数为false来选择不选择的标签。

             actionBar.addTab(tab,false);
            

            我认为出现异常是因为重写了onTabSelected() 方法,如下所示

             viewPager.setCurrentItem(tab.getPosition());
            

            所以当调用addTab() 时,它无法识别要将选项卡添加到哪个viewPager 和适配器。

            【讨论】:

              【解决方案7】:

              将此行添加到您的适配器文件中 公共对象实例化项(ViewGroup 容器,int 位置) 方法被调用

              ((ViewPager) 容器).addView(view); 返回视图;

              【讨论】:

                【解决方案8】:

                请确保 setOffscreenPageLimit 和 getCount 中的值匹配,否则会出现此错误:

                    mViewPager.setOffscreenPageLimit(MAX_TABS);
                
                    public class SectionsPagerAdapter extends FragmentPagerAdapter {
                    ...
                    @Override
                    public int getCount() {
                        return MAX_TABS;
                    }
                

                【讨论】:

                  【解决方案9】:

                  调用 Viewpager.setAdapter(adapter);在您的数组列表中添加项目之后。

                  【讨论】:

                    【解决方案10】:

                    这里要检查的另一件事是它提供此错误检查源列表的适配器是否从其他列表获取引用。

                    您的适配器列表可能是从其他列表中引用的,并且在该列表中已更新并添加了一些项目。

                    【讨论】:

                      猜你喜欢
                      • 2017-05-23
                      • 1970-01-01
                      • 2017-09-24
                      • 1970-01-01
                      • 2017-12-13
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多