Android IllegalStateException: 应用程序的 PagerAdapter 更改了适配器的内容而没有调用 PagerAdapter#notifyDataSetChanged

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22943658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:35:28  来源:igfitidea点击:

IllegalStateException: The application's PagerAdapter changed the adapter's content without calling PagerAdapter#notifyDataSetChanged

androidandroid-viewpagerillegalstateexceptionfragmentpageradapter

提问by Zagorax

I'm using the ViewPagerexample with ActionBartabs taken from the Android documentation here.

我正在使用ViewPager带有ActionBar从 Android 文档here 中获取的选项卡的示例。

Unfortunately, as soon as I call the addTabmethod, the application crashes with the following exception:

不幸的是,一旦我调用该addTab方法,应用程序就会崩溃并出现以下异常:

IllegalStateException: The application's PagerAdapter changed the adapter's content without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count 0, found 1.

IllegalStateException:应用程序的 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged!预期的适配器项数为 0,发现为 1。

This is the FragmentPagerAdaptercode:

这是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) {
        }
    }
}

I'm not modifying my adapter in any other part of my code and I'm calling the addTabmethod from the main thread, the addTabmethod ends with a call to notifyDataSetChanged. As the documentation recommends to do:

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

PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to notifyDataSetChanged() similar to AdapterView adapters derived from BaseAdapter.

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

采纳答案by Zagorax

I had a hard time making my ViewPagerworking. At the end, it seems that the example in the documentation is wrong.

我很难让我的ViewPager工作。最后,似乎文档中的示例是错误的。

The addTabmethod should be as follows:

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

Notice the order of the last three operations. In the original example, notifyDataSetChangedwas called after the mActionBar.addTabfunction.

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

Unfortunately, as soon as you call the addTabon the ActionBar, the first tab you add is automatically selected. Because of this, the onTabSelectedevent is fired and while trying to retrieve the page, it throws the IllegalStateExceptionbecause it notices a discrepancy between the expected item count and the actual one.

不幸的是,只要你拨打addTabActionBar,添加的第一个选项卡被自动选择。因此,该onTabSelected事件被触发,并在尝试检索页面时抛出 ,IllegalStateException因为它注意到预期项目数与实际项目数之间存在差异。

回答by almisoft

I fixed it by callinig notifyDataSetChanged() once and just before next call of getCount():

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

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

}

回答by Daniel Wilson

I was getting this error like you by referencing the tabs within getCount():

通过引用 getCount() 中的选项卡,我遇到了这个错误:

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

When instantiated this should either be passed in as a separate variable, or the pager should be set up afterthe collection has been populated / mutated.

实例化时,这应该作为单独的变量传入,或者应该在集合填充/变异设置寻呼机。

回答by Isa M

try this. I worked

尝试这个。我工作

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

        }

回答by Dhaval Barot

add this line into your adapter file where the public Object instantiateItem(ViewGroup container, int position) method is called

将此行添加到调用 public Object instantiateItem(ViewGroup container, int position) 方法的适配器文件中

((ViewPager) container).addView(view); return view;

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

回答by live-love

Make sure the values in setOffscreenPageLimit and getCount match, otherwise you will get this error:

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

    mViewPager.setOffscreenPageLimit(MAX_TABS);

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

回答by Vibhu Vikram Singh

Call Viewpager.setAdapter(adapter); after item add in your array list.

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

回答by Amt87

I had the same problem in FragmentStatePageradapter. in onResume()When reInitialize the adpater and ViewPager, the same error IllegalStateExceptionwill be shown. The solution:

我在FragmentStatePager适配器中遇到了同样的问题。在onResume()重新初始化适配器和时ViewPagerIllegalStateException将显示相同的错误。解决方案:

When adding tab addtab, choose the tab to be not selected by setting setSelected params to false.

添加 tab 时addtab,通过将 setSelected params 设置为 false 来选择不选择的选项卡。

 actionBar.addTab(tab,false);

I think the exception appeared because of overriding the onTabSelected()method like the following

我认为出现异常是因为覆盖onTabSelected()了如下所示的方法

 viewPager.setCurrentItem(tab.getPosition());

So when calling addTab()it didn't recognize which viewPager and adapter to add the tab to.

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

回答by Gene Bo

My issue wasn't exactly the same, but similar context.

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

I have an AlertDialog getting shown in a layout that has ViewPager and is using AppCompatActivity. I was getting the IllegalStateException and crash when rotating the screen.

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

Thanks to the answers from answer @almisoft and @Zagorax, I tried calling notifyDataSetChanged();right before I show the dialog, and the problem seems to have gone away.

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