Search code examples
androidandroid-viewpagerreloaddrawerlayout

Refresh Viewpager from within the DrawerLayout


Context: I have a drawerLayout that contains a list of cities that I get from Realm. The ViewPager is already displaying that list. You can delete a city directly from the DrawerLayout

Problem: When I delete a city from the DrawerLayout, I call mViewPager.getAdapter().notifyDataSetChanged, the viewPager is not reloaded. Since the drawerLayout is displayed over the ViewPager, there is no reload when you close it and the ViewPager / Realm returns a java.lang.ArrayIndexOutOfBoundsException: rowIndex > available rows: 4 > 4 when I navigate back in it.

Do you have any clue on how I could solve that?

For information purpose, here is how it works: **In the BaseActivity, that contains the DrawerLayout **

mCityListAdapter = new CityListAdapter(getBaseContext(), RealmHelper.getStoredCities(), new CityListAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(int position) {
            mPager.setCurrentItem(position);
            mDrawerLayout.closeDrawers();
        }
    }, new CityListAdapter.OnItemLongClickListener() {
        @Override
        public void onItemLongClick(final int position) {
            final CharSequence[] items = {getString(R.string.action_delete_city)};
            AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);
            builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    RealmHelper.removeCity(RealmHelper.getStoredCities().get(position));
                    mPager.getAdapter().notifyDataSetChanged();
                }
            });
            builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    dialogInterface.cancel();
                }
            });

            builder.setTitle(getString(R.string.delete_city_label));
            builder.show();
        }
    });

In the activity that contains the viewPager

@Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        getLayoutInflater().inflate(R.layout.fragment_pager, mFrameLayout);

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        mPager.addOnPageChangeListener(this);

        mAdapter = new FragmentStatePageSupportAdapter(getSupportFragmentManager(), RealmHelper.getStoredCities().size(), this, RealmHelper.getStoredCities());
        mPager.setAdapter(mAdapter);
        mPager.setOffscreenPageLimit(0);

    }

Edit

I did override getItemPosition and it's called. So not the issue.

The @Override
    public int getItemPosition(Object object) {
        Log.v("results", "called getitempostion");
        return POSITION_NONE;
    }  

Solution

  • You should notify the data set only when a change actually occurs, like so

    mRealmChangeListener = new RealmChangeListener() {
        @Override
        public void onChange(Object element) {
            mCityListAdapter.notifyDataSetChanged();
        }
    }
    
    RealmHelper.getStoredCities().addChangeListener(mRealmChangeListener);
    

    And

    mCityListAdapter = new CityListAdapter(getBaseContext(), RealmHelper.getStoredCities(), new CityListAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(int position) {
           ...
        }
    }, new CityListAdapter.OnItemLongClickListener() {
        @Override
        public void onItemLongClick(final int position) {
            ...
            AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);
            builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    RealmHelper.removeCity(RealmHelper.getStoredCities().get(position));
                    ////mPager.getAdapter().notifyDataSetChanged(); // remove this
                }
            });
            ...
        }
    });
    

    EDIT: okay, I guess in that case you should go the longer route:

    mRealmChangeListener = new RealmChangeListener() {
        @Override
        public void onChange(Object element) {
            mCityListAdapter.notifyDataSetChanged();
        }
    }
    
    RealmResults<City> listenerSet;
    Realm realm;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        realm = Realm.getDefaultInstance();
        listenerSet = realm.where(City.class).findAll();
        listenerSet.addChangeListener(mRealmChangeListener);
    }
    

    Or something of this sort.