How to Remove Fragment from FragmentPagerAdapter?

Clash Royale CLAN TAG#URR8PPPHow to Remove Fragment from FragmentPagerAdapter?
I know there are some topics about this here already but I could not find a solution which I could get to work for my case.
I have a working sliding gallery using a custom FragmentActivity and FragmentPagerAdapter which holds a list of Fragments.
FragmentActivity
FragmentPagerAdapter
Within the FragmentActivity is a ImageView "delete". If clicked, the function deleteMedia() is called which then should remove the current Fragment and the following Fragment should be displayed.
How would I have to do that in my example?
FragmentActivity
ImageView
deleteMedia()
Fragment
Fragment
FragmentActivity:
public class GalleryPagerActivity extends FragmentActivity implements OnClickListener {
private Intent intent;
private SharedPreferences settings;
private PagerAdapter mPagerAdapter;
private ViewPager mPager;
private List<Fragment> fragments;
private List<WhiteboardMedia> wiList;
private int selectedPosition;
private LinearLayout llTop;
private TextView tvTop;
private ImageView delete;
private ImageView share;
private TextView tvCounter;
private TextView tvFilename;
private TextView tvFilesize;
private TextView tvDate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
super.setContentView(R.layout.gallery_pager);
intent = getIntent();
Type collectionType = new TypeToken<List<WhiteboardMedia>>(){}.getType();
wiList = gson.fromJson(intent.getStringExtra("wiList"), collectionType);
selectedPosition = intent.getIntExtra("position", 1);
llTop = (LinearLayout) findViewById(R.id.llTop);
llTop.setOnClickListener(this);
tvTop = (TextView) findViewById(R.id.tvTop);
tvTop.setOnClickListener(this);
delete = (ImageView) findViewById(R.id.imgDelete);
delete.setOnClickListener(this);
share = (ImageView) findViewById(R.id.imgShare);
share.setOnClickListener(this);
tvCounter = (TextView) findViewById(R.id.tvCounter);
tvFilename = (TextView) findViewById(R.id.tvFilename);
tvFilesize = (TextView) findViewById(R.id.tvFilesize);
tvDate = (TextView) findViewById(R.id.tvDate);
createContextMenu();
initDropbox();
} catch (Exception e) {
Log.e("GalleryPagerActivity", e.getLocalizedMessage());
}
}
/**
* Initialise the pager
*/
private void initialisePager() {
mPager = (ViewPager) super.findViewById(R.id.viewpager);
mPager.setAdapter(this.mPagerAdapter);
mPager.setOnPageChangeListener(new GalleryPageListener(tvCounter, tvFilename, tvFilesize, tvDate, wiList));
mPager.setCurrentItem(selectedPosition, true);
updatePage(selectedPosition);
}
public void updatePage(int position)
{
int focusedPage = position + 1;
Log.i("onPageSelected", "page selected " + position);
WhiteboardMedia wiImage = wiList.get(position);
String imageDate = "N/A";
try {
Date dateTaken= new Date(); //wiImage.getDate();
SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd");
imageDate = sdf.format(dateTaken);
} catch (Exception e) {
}
try {
tvCounter.setText(focusedPage + "/" + wiList.size());
tvFilename.setText(wiImage.getFilename());
tvFilesize.setText(wiImage.getSize() + "a");
tvDate.setText(imageDate);
} catch (Exception e) {
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
}
private WhiteboardMedia getActiveWhiteboardImage() {
return wiList.get(mPager.getCurrentItem());
}
private final int DELETE = 1;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, DELETE, 2, R.string.delete).setIcon(R.drawable.menu_btn_trash);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DELETE:
deleteMedia();
return true;
}
return super.onContextItemSelected(item);
}
@Override
public void onClick(View v) {
if (v == delete) {
deleteMedia();
}
}
private void deleteMedia() {
// TODO delete the active Fragment and display the next Fragment in the list
}
/******************************************************************************
* Context Menu
*****************************************************************************/
private void createContextMenu() {
// context menu stuff
}
@Override
protected Dialog onCreateDialog(int id) {
// stuff
}
}
FragmentPagerAdapter:
public class GalleryPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments;
public GalleryPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
@Override
public int getCount() {
return this.fragments.size();
}
}
Thanks for help!
5 Answers
5
First, I suggest that you consider altering your FragmentPagerAdapter, to look more like the sample. You normally do not hold a list of fragments, any more than an ArrayAdapter normally holds a list of Views for the rows. Normally, you create the fragments on demand, and somebody else holds the list.
FragmentPagerAdapter
ArrayAdapter
Views
Then, to delete something, delete it from your model data (what the FragmentPagerAdapter normally wraps). Make sure that getCount() will then return the right number of items. Then, call notifyDataSetChanged() on the FragmentPagerAdapter, which should trigger a redraw of the ViewPager.
FragmentPagerAdapter
getCount()
notifyDataSetChanged()
FragmentPagerAdapter
ViewPager
for (int i = 0; i < wiList.size(); i++) { WhiteboardMedia tmpWi = wiList.get(i); if (tmpWi.getType() == IMAGE) { fragments.add(IMAGE); } else if () { fragments.add(AUDIO); } else if () { fragments.add(VIDEO); } } mAdapter = new MPagerAdapter(getSupportFragmentManager(), fragments);
@user753827:
getItem() would need to have the smarts to return the right fragment.– CommonsWare
Mar 19 '12 at 9:59
getItem()
Ugh, I've been having the same problem for ages. The fragments don't get collected and stay there visually (in their old and wrong position) until I scroll too far right/left and the system culls them and resyncs. Any idea what I'm doing wrong? My code looks pretty much like the example.
– Stavros Korokithakis
Jun 20 '13 at 3:23
@StavrosKorokithakis: Adding and removing fragments was sufficient of a pain that I eventually wrote
ArrayPagerAdapter to try to provide a better solution: github.com/commonsguy/cwac-pager It's still early days for the component, but it holds promise.– CommonsWare
Jun 20 '13 at 11:06
ArrayPagerAdapter
@CommonsWare Oh that looks fantastic, thank you! I just got the
FragmentPagerAdapter working (needed a FragmentStatePager in the end, the vanilla FragmentPagerAdapter doesn't like removing fragments), but I'll use your component next time, thank you!– Stavros Korokithakis
Jun 20 '13 at 17:46
FragmentPagerAdapter
FragmentStatePager
FragmentPagerAdapter
that is the solution I'm using:
mViewPager : is the view you are using to set you Fragment
mViewPager = (YourViewPager) findViewById(R.id.myPager);
TABLE : is just a Integer list of the position of all my Fragments
public void destroyAllItem() {
int mPosition = mViewPager.getCurrentItem();
int mPositionMax = mViewPager.getCurrentItem()+1;
if (TABLE.size() > 0 && mPosition < TABLE.size()) {
if (mPosition > 0) {
mPosition--;
}
for (int i = mPosition; i < mPositionMax; i++) {
try {
Object objectobject = this.instantiateItem(mViewPager, TABLE.get(i).intValue());
if (objectobject != null)
destroyItem(mViewPager, TABLE.get(i).intValue(), objectobject);
} catch (Exception e) {
Log.i(TAG, "no more Fragment in FragmentPagerAdapter");
}
}
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
if (position <= getCount()) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
}
This works for me, thanks!
– Konstantin Konopko
Nov 11 '15 at 14:22
Perfect Douarbou ! Thanks !
– anthony
Dec 30 '15 at 6:24
Works like charm! Saved My time! Thank you :)
– Vivek Solanki
Mar 21 '17 at 14:26
I found a solution ovverriding the method "onPostResume()" of the activity and calling the notifyDataSetChanged inside that.
@Override
protected void onPostResume() {
super.onPostResume();
if(this.mCustomPagerAdapter!=null){
this.mCustomPagerAdapter.notifyDataSetChanged();
}
}
If you are using FragmentPagerAdapter for adding and removing fragments at random position(not always at the end) dynamically, there is a method you need to taken more attention which is getItemId. By default, FragmentPagerAdapter uses position combines viewId as the tag name for fragments, however the position changes if you add or remove fragments. As a result, you may get an empty page because the position you are adding is occupied by an existing fragment. To solved this problem, override getItemId.
@Override
public long getItemId(int position) {
long itemId = ...; //Provide your unique ID here according to you logic
return itemId;
}
After getting the itemId do I have to manually remove each Item from the FragmentPagerAdapter? Is there any other way to automatically update FragmentPagerAdapter based on the Model data?
– Slick Slime
Jun 22 at 12:56
What you need to do is call the notifyDatasetChanged on the adapter after adding or removing fragments. Not sure this answers your "automatically" question.
– Jason
Jun 26 at 17:47
In my case, when i try to remove one item from the adapter, i will do as follow:
// get the position of item to remove
int position = getBinding().vp.getCurrentItem();
// remove the item from adapter
adapter.removeItem(position);
adapter.notifyDataSetChanged();
// minus one from the count
totalInvoice--;
updateTitle(getBinding().vp.getCurrentItem());
if (totalInvoice == 0) {
finish();
}
// set the adapter to view pager again
getBinding().vp.setAdapter(adapter);
// smooth scroll to given position
getBinding().vp.setCurrentItem(position);
The reason that i did above is that i find that even though you removed one from the data list, but the view of fragment still exist. So you have to let the view pager instantiate the view of given position. The answer above which trying to remove all fragments doesn't work for me. So, I find out the poor way of setting adapter to view pager again.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
OK thanks so far! Trying to get my code like in the example. In my code I go through a Object-List and fill the Fragment List with the proper Fragments (Image, Audio, Video).
for (int i = 0; i < wiList.size(); i++) { WhiteboardMedia tmpWi = wiList.get(i); if (tmpWi.getType() == IMAGE) { fragments.add(IMAGE); } else if () { fragments.add(AUDIO); } else if () { fragments.add(VIDEO); } } mAdapter = new MPagerAdapter(getSupportFragmentManager(), fragments);Where do I have to place this code? In the example it looks like the Fragments are all the same type.– e-nature
Mar 19 '12 at 8:55