1

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 PopupHandlerclass 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();
            }
    }
}
Community
  • 1
  • 1
Ofek Agmon
  • 5,040
  • 14
  • 57
  • 101

0 Answers0