I recently started to program an app which uses ViewPager. I'm currently stuck with adding new data to the Adapter. My problem is, that if I add new data to the Array lists of my adapter, the view will be created but shows strange behaviour. I can scroll to it, but once I try to get away from my page, the app will crash in an overflow error. I debugged the App and noticed, that the InstanciateItem() method will not be called. Therefore the data will be added to my Arraylist but no view gets created. This behaviour does not change when I call InstanciateItem() manually, besides the fact that the view gets created this time.
During startup in the onCreate() method of my mainActivity I will execute the following code:
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mCardAdapter = new CardPagerAdapter(this, mViewPager);
mCardAdapter.addCardItem(new CardItem("test1", "ip : 123.123.1.1", "status active"));
mViewPager.setAdapter(mCardAdapter);
This card will be added and they are fully functional during scroll operation. Later in MainActivity, I will execute the following code:
if(!name.isEmpty() && !IP.isEmpty() && !PW.isEmpty()){
mCardAdapter.addCardItem(new CardItem(name,IP,"status active"));
mCardAdapter.instantiateItem(mViewPager,mCardAdapter.mData.size()-1);
System.out.println(mCardAdapter.mViews + " "+ mCardAdapter.mData);
dialog.dismiss();
}
This time it behaves as I described, it does not matter if I call instantiateItem() manually or not, the behaviour is the same.
I will post you the code of my Adapter, maybe you can help me out here.
public class CardPagerAdapter extends PagerAdapter implements CardAdapter {
ViewPager viewPager;
MainActivity mainActivity;
public List<CardView> mViews;
public List<CardItem> mData;
private float mBaseElevation;
public CardPagerAdapter(MainActivity mainActivity, ViewPager viewPager) {
mData = new ArrayList<>();
mViews = new ArrayList<>();
this.mainActivity = mainActivity;
this.viewPager = viewPager;
}
public void addCardItem(CardItem item) {
mViews.add(null);
mData.add(item);
notifyDataSetChanged();
}
public void deleteCardItem(int position){
mData.remove(position);
mViews.set(position, null);
notifyDataSetChanged();
}
public float getBaseElevation() {
return mBaseElevation;
}
@Override
public CardView getCardViewAt(int position) {
return mViews.get(position);
}
@Override
public int getCount() { return mData.size();}
@Override
public int getNumberOfCards() {return mViews.size();}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
mViews.remove(position);
}
@Override
public int getItemPosition(@NonNull Object object) {
int position = mViews.indexOf(object);
if(position == -1){
return POSITION_NONE;
}else{
return position;
}
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Button deleteButton;
Button editButton;
View view = LayoutInflater.from(container.getContext()).inflate(R.layout.device_card_layout,
container, false);
deleteButton = view.findViewById(R.id.deleteButton);
editButton = view.findViewById(R.id.editButton);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("fetus deletus");
deleteCardOperation(viewPager.getCurrentItem(), container);
}
});
editButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("edit");
int currentCard = viewPager.getCurrentItem();
}
});
container.addView(view);
bind(mData.get(position), view);
CardView cardView = (CardView) view.findViewById(R.id.itemCard);
if (mBaseElevation == 0) {
mBaseElevation = cardView.getCardElevation();
}
cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
mViews.set(position, cardView);
return view;
}
private void bind(CardItem item, View view) {
TextView titleTextView = (TextView) view.findViewById(R.id.itemText);
TextView ipTextView = (TextView) view.findViewById(R.id.itemIPAdress);
TextView statusView = (TextView) view.findViewById(R.id.itemActiveStatus);
titleTextView.setText(item.getName());
ipTextView.setText(item.getIp());
statusView.setText(item.getStatus());
}
private void deleteCardOperation(int position, ViewGroup desV){
CardItem x = mData.get(position);
AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity,
android.R.style.Theme_Material_Dialog_Alert);
builder.setTitle("Confirm");
builder.setMessage("Are you sure you want to delete this device: "+ x.getName() + " ?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
deleteCardItem(position);
dialog.dismiss();
}
});
builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
My problem is, that i do not understand, why the code behaves so differently. I just searched though many of the suggestions made here on StackOverflow but can not find a conclusion for me. Maybe im just missing something. I would be glad for any suggestion or help with my problem.
Its been a few days from where I asked this question and I still didn't manage to get the ViewPager to work. The problem seems to be, that ViewPager itself is not serviced any more by google. ViewPager has a Problem with update handling. But this issue will not be fixed, bc its not going to be updated by Google. They simply created the ViewPager2 structure, which is based on the recyclerView. I tried switching to the new ViewPager and it worked directly. No problems with dynamically adding, removing or updating cards. Its very simple with that.
For everyone who is stuck with the same problem, I recommend switching to ViewPager2. It's much more convenient than the old ViewPager. Plus, the new ViewPager2 is not very different from the old one, besides the changed backend.