I am using FragmentPagerAdapter and I need to refresh the content after user action.
To do this, I am calling notifyDataSetChanged() on the adapter but nothing seems happen. I would like to avoid using FragmentStatePagerAdapter, since it contains just 3 pages.
Here is the override methods of the adapter:
#Override
public int getCount() {
return 3;
}
#Override
public Fragment getItem(int position) {
Fragment fragment;
switch (position) {
case PAGE_HOME:
fragment = HomeFragment.newInstance();
break;
case PAGE_CATEGORIES:
fragment = CategoriesFragment.newInstance();
break;
case PAGE_ACCOUNT:
if (account == null) {
fragment = AccountFragment.newInstance();
} else {
fragment = MyAccountFragment.newInstance();
}
break;
default:
fragment = null;
}
pageReferenceMap.put(position, fragment);
return fragment;
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
pageReferenceMap.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
pageReferenceMap.remove(position);
}
Thanks.
I found out that I have to return a different id for that page position. So here is how I return a unique id based on the fragment I want to display and not based on the page position:
#Override
public long getItemId(int position) {
long id;
switch (position) {
case HOME_PAGE_POSITION:
//fall through
case CATEGORIES_PAGE_POSITION:
id = position;
break;
case ACCOUNT_PAGE_POSITION:
if (account == null) {
id = position;
} else {
id = position + PAGE_COUNT;
}
break;
default:
id = -1;
}
return id;
}
If you have more that 2 fragments per pages to display at a time, you can just return position+PAGE_COUNT*n. Pretty easy.
Hope this help.
notifyDataSetChanged method will send a call back to your adapter , and check for the getCount method following this call back the getItem method is called. Your content in the screen refresh only if the content reflect any change in the currently selected fragment.The point to note here is that This callback will not select your first fragment. It will stay in the currently selected fragment.
For example:-
The currently selected fragment is 2, and you have changed the contents of fragment number 1 and makes a notifyDataSetChanged callback, so in this case you will not see any change as fragment 2 is currently present in the screen.
Related
I have a view pager which I need to refresh it's components which are three fragments.
I want to remove the views and adding new views
The setadapter method throws
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Although I remove all views from the pager before setting the new adapter
viewPager.removeAllViews();
viewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager()));
The Adapter code is as follows
public class SampleFragmentPagerAdapter extends FragmentStatePagerAdapter {
final int PAGE_COUNT = 3;
SettingRTL settingRTL = new SettingRTL();
private String tabTitles[] = new String[]{"News", "Articles", "Reports"};
private String tabTitlesA[] = new String[]{"الأخبار", "المقالات", "التقارير"};
public SampleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return PromosFragment.newInstance(0, "Page # 1");
case 1:
return ArticlesFragment.newInstance(1, "Page # 2");
case 2:
return OtherFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
if (settingRTL.getCurrentLang().equals("العربية")) {
return tabTitlesA[position];
}
return tabTitles[position];
}
Because you need to override in your SampleFragmentPagerAdapter:
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
You can override viewPager.addOnPageChangeListener() inside your Fragment.
and then do the needful to create newInstance of Fragment/Activity. whenever the page got changed you can perform your operation for creating new instance of Fragment.
Following this example I'm trying to replace one fragement with another within a single tab of a ViewPager. I'm getting this exception:
java.lang.IllegalStateException: Can't change tag of fragment DailyWordFragment
class ViewPagerAdapter extends FragmentPagerAdapter {
private final FragmentManager fragmentManager;
Fragment fragment;
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
fragmentManager = manager;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
if(fragment == null){
fragment = DailyWordFragment.newInstance();
}
return fragment;
case 1:
if(fragment == null){
fragment = WordListFragment.newInstance(new WordListFragment.OnWordItemAddListener() {
#Override
public void onWordItemAddListener() {
fragmentManager.beginTransaction().remove(fragment).commit();
fragment = AddWordFragment.newInstance();
notifyDataSetChanged();
}
});
}
return fragment;
default:
return null;
}
}
#Override
public int getItemPosition(Object object) {
if(object instanceof WordListFragment && fragment instanceof AddWordFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
#Override
public int getCount() {
return 2;
}
}
According to other posts this exception seems to be caused by adding the same fragment repeatedly, or getting miscounting the number of fragments but I can't see where either of these are occurring if at all? Clearly I'm missing something. I would appreciate any help. Thank you.
Have you tried before you initialize the Fragment to set it to null?
#Override
public Fragment getItem(int position) {
fragment = null
switch (position){
case 0:
if(fragment == null){
fragment = DailyWordFragment.newInstance();
}
return fragment;
case 1:
if(fragment == null){
fragment = WordListFragment.newInstance(new WordListFragment.OnWordItemAddListener() {
#Override
public void onWordItemAddListener() {
fragmentManager.beginTransaction().remove(fragment).commit();
fragment = AddWordFragment.newInstance();
notifyDataSetChanged();
}
});
}
return fragment;
default:
return null;
}
}
To SWAP fragments in one tab of a View Pager you have to do it in a different way:
You need a fragment that goes in the ViewPager that acts as a container. which is managed by the ViewPager. This Fragment is allways there in the tab, never swaps or changes.
Inside that Fragment you have 2 child fragments that you can swap using transactions with the ChildFragmentManager. But the ViewPager doesn't even know about their existance.
I'm using fragmentpageradapter to inflate fragment , this is my coding.
i'm adding cart item in one fragment and showing it to other fragment and all fragment comes in tab layout.My problem is cart item is not refreshing on other fragment while swiping fragment.
public class ProfileDetailePagerAdapter extends FragmentPagerAdapter
{
int TabCount;
HashMap<Integer, String> mFragmentTags;
FragmentManager mFragmentManager;
private boolean isPagingEnabled = true;
public ProfileDetailePagerAdapter(FragmentManager fm, int TabCount) {
super(fm);
this.TabCount = TabCount;
mFragmentTags = new HashMap<Integer, String>();
mFragmentManager = fm;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
MenuFragment tab1 = new MenuFragment();
return tab1;
case 1:
SelectMember_fragment tab2 = new SelectMember_fragment();
return tab2;
case 2:
ViewCart_fragment tab3 = new ViewCart_fragment();
return tab3;
/* case 3:
PaymentMode_fragment tab4=new PaymentMode_fragment();
return tab4;*/
}
return null;
}
#Override
public int getCount() {
return TabCount;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
}
Call FragmentStatePagerAdapter
You should use addOnTabSelectedListener
This method is used to add a listener that will be invoked when tab
selection changes.
tabLayoutOBJ.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
public void onTabReselected(TabLayout.Tab tab) {
}
public void onTabSelected(TabLayout.Tab tab){
String getTAB = (String)tab.getText();
// Do your WORK
}
public void onTabUnselected(TabLayout.Tab tab){
}
});
The reason behind it is the implementation of viewpager. There is a property called offset in ViewPager to make ready fragments next to it up to offset(int) value.
Default value is 1. For example, you are in 1st position, 0th and 2nd positions are also created.
On the other hand if you are in 0th position 1st is the only created fragment. If you swipe to right (going 1st) then 2nd is going to be created.
I assume you are changing a shared object from 1st fragment and want to notify 2nd fragment with changed data. To solve it you need to use listener. The elegant way to solve it is adding observer pattern to your shared object.
Good luck
Emre
I am trying to update a view pager using FragmentPagerAdapter. Every time I call notifyDataSetChanged from my adapter I get a force close with this error "java.lang.IllegalStateException: Recursive entry to executePendingTransactions".
Any pointers on this would be helpful I have posted code below and I will post 2 links to 2 other questions I have had on this topic after this. Updating this ViewPager has been giving me a serious headache so any advice would be appreciated.
Removing Tabs using FragmentPagerAdapter ,
https://stackoverflow.com/questions/32834861/adding-and-removing-tabs-using-fragmentpageradapter
public void setTabsToSHow() {
Toast.makeText(getActivity(), Integer.toString(listOfTitles.size()), Toast.LENGTH_LONG).show();
mViewPager.getAdapter().notifyDataSetChanged();
}
class TabPageAdapter extends FragmentPagerAdapter {
public TabPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case JudgeActivity.JUDGE_MAIN:
if (mMainFragment == null) {
mMainFragment = JudgeMainFragment.newInstance();
}
return mMainFragment;
case JudgeActivity.JUDGE_VERDICTS:
if (mVerdictFragment == null) {
mVerdictFragment = JudgeVerdictFragment.newInstance();
}
return mVerdictFragment;
case JudgeActivity.JUDGE_CLASSIFY:
if (mClassifyFragment == null) {
mClassifyFragment = JudgeClassifyFragment.newInstance();
}
return mClassifyFragment;
case JudgeActivity.JUDGE_SIDEBAR:
if (mSidebarFragment == null) {
mSidebarFragment = JudgeSidebarFragment.newInstance((SidebarCall) mActivity);
}
return mSidebarFragment;
}
return null;
}
#Override
public int getCount() {
return listOfTitles.size();
}
#Override
public int getItemPosition(Object object) {
Toast.makeText(getActivity(), "itempostioton",Toast.LENGTH_SHORT).show();
return POSITION_NONE ;
}
#Override
public CharSequence getPageTitle(int position) {
// return CONTENT[position % CONTENT.length].toUpperCase(Locale.US);
//Notify data set changed can only be called from inside this class
notifyDataSetChanged();
return listOfTitles.get(position);
}
}
Remove notifyDataSetChanged(); from public CharSequence getPageTitle(int position) method
Secondly, do not return from case statements, rather do assignment to local variable and finally return the fragment. Use break after every case block.
I have two ViewPagers First have 5 Views (Fragments) and Second Have 3 Fragments inside a single java file. The problem is when second view shows Fragment 1st then i can only access 3 Fragments of First ViewPager 1-3 and when second View Pager is showing 3rd Fragment then can access only 3-5 fragment means can access only 3 fragment at a time.
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
//Log.e("Position", position+"");
if(position==0){
fragment=new AssetSelectionFragmentWallpaper();
}
else{
fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
args.putInt(DummySectionFragment.ARG_OBJECT, position+1);
fragment.setArguments(args);
}
return fragment;
}
#Override
public int getCount() {
// Show 5 total pages.
return 5;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
case 3:
return getString(R.string.title_section4).toUpperCase(l);
case 4:
return getString(R.string.title_section5).toUpperCase(l);
}
return null;
}
#Override
public int getItemPosition(Object object) {
if (object instanceof UpdateableFragment) {
((UpdateableFragment) object).update(null);
}
if(object instanceof AssetSelectionFragmentWallpaper){
return POSITION_NONE;
}
return super.getItemPosition(object);
}
}
public class SectionsPagerAdapter1 extends FragmentStatePagerAdapter {
private Fragment fragment;
private Swipe sw;
public SectionsPagerAdapter1(FragmentManager fm, Swipe s) {
super(fm);
this.sw = s;
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
fragment = new DummySectionFragment1();
Bundle args = new Bundle();
args.putInt(DummySectionFragment1.ARG_SECTION_NUMBER, position + 1);
args.putInt(DummySectionFragment1.ARG_OBJECT, position+1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return "SETTINGS";
case 1:
return "SHOP";
case 2:
return "CONTACTS";
case 3:
return "";
}
return null;
}
#Override
public int getItemPosition(Object object) {
// don't return POSITION_NONE, avoid fragment recreation.
return super.getItemPosition(object);
}
}
Every Object Name is Different and Globally Declared...
I think getCount() Function is conflicting to each other.
Please Help to resolve this...
Thanks...
I think you should check your XML first, if there you find any problem. or
You can fix also by declaring any RONDOM ID like _pager.setId(int);