So first things first, here's the error that I'm getting:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 18, found: 28
I'm using a RecyclerView
in my main activity and that has a List<Objects>
as the dataset, that's all fine.
From that activity I call the second activity when a RecyclerView item is clicked that is basically a gallery implemented using a ViewPager
using this code:
public void startSlideActivity(final int position) {
DataTransferer.get().storeItems(feed);
Intent i = new Intent(context, SlideActivity.class);
...
i.putExtra("POSITION", position);
context.startActivity(i);
}
My data is too large to transfer through an intent (using Parcelable or otherwise) so I'm using a singleton to hold and transfer my list, here's the code:
public class DataTransferer {
private static volatile DataTransferer singleton;
private List<Thing> items;
public static DataTransferer get(){
if (singleton == null) {
synchronized (DataTransferer.class) {
singleton = new DataTransferer();
}
}
return singleton;
}
private DataTransferer(){
}
public void storeItems(List<Thing> items){
this.items = items;
}
public List<Thing> getStoredItems(){
return items;
}
}
In the second activity I set the adapter and retrieve the list like so:
feed = DataTransferer.get().getStoredItems();
final int position = this.getIntent().getIntExtra("POSITION", 0);
adapter = new FeedPagerAdapter(SlideActivity.this, feed);
viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
viewPager.setCurrentItem(position);
viewPager.setOffscreenPageLimit(4);
And finally here's in my PagerAdapter code:
public class FeedPagerAdapter extends PagerAdapter {
@BindView(R.id.item_image_view) ImageView image;
private final SlideActivity host;
private List<Thing> items;
public FeedPagerAdapter(SlideActivity host, List<Thing> items){
this.host = host;
this.items = items;
notifyDataSetChanged();
}
@Override
public Object instantiateItem(ViewGroup parent, int position) {
View view = LayoutInflater.from(host).inflate(R.layout.item, parent, false);
ButterKnife.bind(this, view);
...
parent.addView(view);
return view;
}
@Override
public int getCount() {
return items.size();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
I've tried notifying the dataset in onResume
and onPause
and getItemCount in the adapter also, same problem.
Back to the main activity, this data is loaded over the network and adds items to the list when the load finishes. If I start my application and click on the item as soon they start to populate the RecyclerView, it opens the second activity and I get the crash. If I start the app and wait a second and click a RecyclerView item, it works as intended.
If anyone has any suggestions on how I can wait to make sure the list is stable when starting the second activity or a better way to implement a grid based RecyclerView gallery to open a viewpager type layout with the same dataset I would really appreciate it.
It's because you are using this line
viewPager.setOffscreenPageLimit(4);
, It's mean viewpager won't re-create the screen in all 4 pages. However, there is a function to detect if your screen has been visible completely, it's callsetUserVisibleHint()
. You just need to use like below: //For the Fragment caseEDIT:
android.app.Application.ActivityLifecycleCallbacks
In your
finish()
method, you want to useisActivityVisible()
to check if the activity is visible or not. There you can also check if the user has selected an option or not. Continue when both conditions are met.