I have a Custom PageAdapter that is dynamic and lets you add and remove views. I found the code from this answer.
MainPagerAdapter
public class MainPagerAdapter extends PagerAdapter {
private ArrayList<View> views = new ArrayList<View>();
@Override
public int getItemPosition(Object object) {
int index = views.indexOf(object);
if (index == -1)
return POSITION_NONE;
else
return index;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View v = views.get(position);
container.addView(v);
return v;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public int addView(View v) {
return addView(v, views.size());
}
public int addView(View v, int position) {
views.add(position, v);
return position;
}
public int removeView(ViewPager pager, View v) {
for (int i = 0; i < views.size(); i++) {
if (views.get(i).getTag().equals(v.getTag()))
return removeView(pager, i);
}
return -1;
}
public int removeView(ViewPager pager, int position) {
pager.setAdapter(null);
views.remove(position);
pager.setAdapter(this);
return position;
}
public View getView(int position) {
return views.get(position);
}
}
Basically I have the PopupHandler
class which calls showDialog
once, for the first alert, and after that it calls AddView
to add more pages, and removeView
to remove a page.
Every time the PopupHandler
gets an alert, it checks some conditions and either adds another view or remove an existing one.
The problem I have is : sometimes when pages are added and I slide between the pages, the app crashes, saying
The specified child already has a parent. You must call removeView() on the child's parent first.
I cant say exactly when it happens, sometimes I am able to re-create the error, but the log shows the error is in this method, in the line container.addView(v);
@Override
public Object instantiateItem(ViewGroup container, int position) {
View v = views.get(position);
container.addView(v); // here is the crash
return v;
}
Also, here is the PopupHandler (class populating the ViewPager
and adding views):
public class PopupHandler {
private Context context;
private boolean isPopUpShowing;
private List<AlarmType> alarmTypeList;
private ViewPager pager = null;
private MainPagerAdapter pagerAdapter = null;
private View verticalLineSeperator;
private TextView alertNumber;
private AlertDialog alertDialog;
public PopupHandler(Context context) {
this.context = context;
...
}
public void handleAlert(IAlarmInfo alarmInfo) {
// checking some conidtions
if (newAlarm) {
alarmTypeList.add(alarmInfo.getAlarmType());
if (...) {
// first time creating dialog and adding view
showDiaog(alarmInfo.getTitle(), alarmInfo.getSummary(), alarmInfo.getAlarmIconResource(), alarmInfo.getAlarmType());
isPopUpShowing = true;
} else {
// adding view
View v = setUpView(alarmInfo.getTitle(), alarmInfo.getSummary(), alarmInfo.getAlarmIconResource(), alarmInfo.getAlarmType());
addView(v);
}
} else {
if (alarmTypeList.contains(alarmInfo.getAlarmType())) {
//remove view
alarmTypeList.remove(alarmInfo.getAlarmType());
View v = setUpView(alarmInfo.getTitle(), alarmInfo.getSummary(), alarmInfo.getAlarmIconResource(), alarmInfo.getAlarmType());
removeView(v);
if (alarmTypeList.size() == 0 && alertDialog.isShowing()) {
// if list empty dismiss dialog
alertDialog.dismiss();
isPopUpShowing = false;
}
}
}
}
private void showDiaog(final String title, final String summary, final int icon, AlarmType alarmType) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
dialogBuilder.setCancelable(false);
LayoutInflater inflater = LayoutInflater.from(context);
View dialogView = inflater.inflate(R.layout.popups_container, null);
ButterKnife.bind(this, dialogView);
pager = (ViewPager) dialogView.findViewById(R.id.popup_view_pager);
pager.setAdapter(pagerAdapter);
pager.setOffscreenPageLimit(5);
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Log.i("testing", "onPageSelected " + position);
alertNumber.setText((position + 1) + " of " + pagerAdapter.getCount());
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
alertNumber = (TextView) dialogView.findViewById(R.id.popup_alert_number);
alertNumber.setText((alarmTypeList.indexOf(alarmType) + 1) + " of " + alarmTypeList.size());
verticalLineSeperator = dialogView.findViewById(R.id.popup_vertical_seperator);
verticalLineSeperator.setBackgroundColor(alertNumber.getTextColors().getDefaultColor());
View v = setUpView(title, summary, icon, alarmType);
pagerAdapter.addView(v, 0);
pagerAdapter.notifyDataSetChanged();
dialogBuilder.setView(dialogView);
alertDialog = dialogBuilder.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.show();
}
private View setUpView(String title, String summary, int icon, AlarmType alarmType) {
View v1 = LayoutInflater.from(context).inflate(R.layout.popup, null);
TextView titleText = (TextView) v1.findViewById(R.id.popup_title);
TextView summaryText = (TextView) v1.findViewById(R.id.popup_summary);
ImageView iconText = (ImageView) v1.findViewById(R.id.popup_alert_icon);
titleText.setText(title);
summaryText.setText(summary);
iconText.setImageResource(icon);
v1.setTag(alarmType);
return v1;
}
public void addView(View newPage) {
int pageIndex = pagerAdapter.addView(newPage);
pagerAdapter.notifyDataSetChanged();
pager.setCurrentItem(pageIndex, true);
}
public void removeView(View defunctPage) {
int pageIndex = pagerAdapter.removeView(pager, defunctPage);
// You might want to choose what page to display, if the current page was "defunctPage".
if (pageIndex == -1)
return;
if (pageIndex == pagerAdapter.getCount())
pageIndex--;
pager.setCurrentItem(pageIndex);
alertNumber.setText((pageIndex + 1) + " of " + alarmTypeList.size());
}
public View getCurrentPage() {
return pagerAdapter.getView(pager.getCurrentItem());
}
public void setCurrentPage(View pageToShow) {
pager.setCurrentItem(pagerAdapter.getItemPosition(pageToShow), true);
}
public void hidePopup() {
if (alertDialog != null)
if (alertDialog.isShowing()) {
alertDialog.dismiss();
alarmTypeList.clear();
}
}
}