12

I am trying to use a static class to pass value to a view instead of using intent as I have to pass a large amount of data. Sometimes I get this error and couldn't find out what is the main reason

Error :-

java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 101, found: 200

My Pager class

public class MemeDetailActivity extends AppCompatActivity implements OnDialogClickListner<Void> {
    private ViewPager mPager;
    private List<Datum> mList;
    private ScreenSlidePagerAdapter pagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_meme_detail);
        mList = DataResult.getInstance().getData();
        DataResult.getInstance().resetData();
        if (mList != null)
            startPager(selected_position);
        else
            Toast.makeText(this, "Error loading data", Toast.LENGTH_SHORT).show();
        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
    }

    private void startPager(int position) {
        pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(pagerAdapter);
        pagerAdapter.notifyDataSetChanged();
        mPager.setOffscreenPageLimit(0);
        mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                new Interactors(MemeDetailActivity.this).updateView(Util.getAccessToken(), mList.get(position).getId(), new OnFinishListner<ViewsRM>() {
                    @Override
                    public void onFinished(ViewsRM result) {

                    }

                    @Override
                    public void onFailed(String msg) {
                    }
                });
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        mPager.setCurrentItem(position);
    }

    public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

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


        //todo entry point 3 : showing the image in the viewpager
        @Override
        public Fragment getItem(int position) {
            Fragment fragment = new fragment_mypager_new();
            Bundle bundle = new Bundle();
            if (frmMyMemes)
                bundle.putParcelable("MY_DATA", myList);
            bundle.putSerializable("DATA", mList.get(position));
            fragment.setArguments(bundle);
            return fragment;
        }

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

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment fragment = (Fragment) super.instantiateItem(container, position);
            registeredFragments.put(position, fragment);
            return fragment;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            registeredFragments.remove(position);
            super.destroyItem(container, position, object);
        }

        public Fragment getRegisteredFragment(int position) {
            return registeredFragments.get(position);
        }
    }

}

My static class

public class DataResult<T> {

    private static DataResult instance;
    private List<T> data = null;

    protected DataResult() {

    }

    public static synchronized DataResult getInstance() {
        if (instance == null) {
            instance = new DataResult();
        }
        return instance;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public void resetData() {
        data = null;
    }
}

How I call the activity

    Intent intent = new Intent(getActivity(), MemeDetailActivity.class);
    DataResult.getInstance().setData(mListA);
viper
  • 1,836
  • 4
  • 25
  • 41
  • 1
    is the data in `mListA` ever modified (added to) after to call `DataResult.getInstance().setData(mListA);`? – David Wasser Feb 03 '17 at 16:40
  • David Wasser's comment point at the correct solution - you shouldn't use static fields to communicate between Activity/Fragment like that. Use intents, content providers etc. like you're supposed to do. Then you can optimize later if you need. If you have this list in the static class and you are modifying it after it has been set in the adapter, it explains exactly the error you are getting. Otherwise, follow the steps in this question: https://stackoverflow.com/questions/22943658/illegalstateexception-the-applications-pageradapter-changed-the-adapters-cont – David Rawson Feb 04 '17 at 04:42

6 Answers6

1

look at your code:

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

this code is use to refresh view when view change. it is also called notifyDataSetChanged()

its optional ovverride method so you can remove it.

Take a look at this answer: ViewPager PagerAdapter not updating the View

or else you can Change the FragmentStatePagerAdapter to FragmentPagerAdapter

Community
  • 1
  • 1
Sagar Chavada
  • 5,169
  • 7
  • 40
  • 67
  • Didn't work for me. It still crashes. The problem that i found is whenever I get data from the api, I add it to the list and if at the same time the user clicks on an item then there I am passing all the data of the list. So if currently there are 100 data in the list and user clicks on an item and at the same time the list gets updated with 99 more data then there will be conflict on the total number of data. It is the same code as I have provided in the question. Could you please suggest me how to solve this issue. – viper Jan 10 '17 at 04:25
  • you should store mList to adapter first and then call notifydatasetchange(); i cant find anywhere that you are storing mList to adapter. – Sagar Chavada Jan 10 '17 at 04:39
  • your problem is this line.. pagerAdapter.notifyDataSetChanged();, – Sagar Chavada Jan 10 '17 at 04:41
  • So you mean I will have to delete the pagerAdapter.notifyDataSetChanged() code? – viper Jan 10 '17 at 04:55
  • I have set data to adapter but haven't provided the code in the question. `mAdaptor = new DetailViewAdaptor(this.mList, this); mRecyclerView.setAdapter(mAdaptor);` – viper Jan 10 '17 at 04:57
1

Sometimes this error occurs.

Here is my suggestion:

In your DataResult->getData()

return a copy of the data.

DataResult is a singleton and holds the data. When your view gets the data, the view gets the data reference witch the DataResult is holding. Then setData() would change the data reference. Here comes the IllegalStateException.

Hope it would work :)

Rust Fisher
  • 331
  • 3
  • 12
0

I think your DataResult class is not necessary.

According to your comment you are getting the error while you are updating the data set. I think you are getting data from some REST API or another web service. Then assign the data you gets from the API to a temporary Array List and update that temporary array list while you are getting new data. Don't touch the mListA variable until you finish receiving data. After complete getting data from the API assign the temporary array list you used to mListA directly in one line.

mListA = tmpList;

Then again call

mList = mListA;
pagerAdapter.notifyDataSetChanged();

This should solve your error.

Dulaj Atapattu
  • 448
  • 6
  • 23
0

try using the following way:

mList=new ArrayList<Datum>();
        mList.addAll(DataResult.getInstance().getData());
        DataResult.getInstance().resetData();
Anuj J Pandey
  • 656
  • 1
  • 4
  • 17
0

It may because you first setAdapter() and notifyDataSetChanged in method initUI();

Then, you instantiate the List<?> data in method initData(), the two methods in different lifetime of fragment.

It's the problem about fragment's lifecycle

Employee
  • 3,109
  • 5
  • 31
  • 50
0
@Override
public void restoreState(Parcelable state, ClassLoader loader) {}
@Override
public Parcelable saveState() {return null;}
#Add in your adapter after getCount();
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40