I am setting up the fragment A,B thru FragmentStatePagerAdapter and having activity with FragmentActivity inside
Acitivity#onCreate
journeyDetailInfos = Manager.INSTANCE.getSeatOffline();
binding = DataBindingUtil.setContentView(this, R.layout.layout);
viewModel = ViewModelProviders.of(this).get(XYZModelView.class);
binding.pager.setAdapter(new SeatJourneyAdapter(this, getSupportFragmentManager(), journeyDetailInfos));
binding.pager.setOffscreenPageLimit(10);
binding.pager.addOnPageChangeListener(this);
binding.tablayout.setupWithViewPager(binding.pager);
binding.tablayout.setOnClickListener(view -> onTabChange());
lastSelectedPage = binding.tablayout.getSelectedTabPosition();
int length = binding.tablayout.getTabCount();
for (int i = 0; i < length; i++) {
binding.tablayout.getTabAt(i).setCustomView(getTabView(i));
}
SeatJourneyAdapter.java Adpater has following code
HashMap<Integer,XYZFragment> fragments;
ArrayList<JourneyDetailsInfo> journeyDetailInfos;
Context context;
private int container_id;
HashMap mFragmentTags ;
SeatJourneyAdapter(Context context, FragmentManager fragmentManager, ArrayList<JourneyDetailsInfo> journeyDetailInfos)
{
super(fragmentManager);
frgaments = new HashMap<Integer,XYZFragment>();
this.journeyDetailInfos = journeyDetailInfos;
mFragmentTags = new HashMap<Integer, String>();
}
#Override
public Fragment getItem(int position) {
XYZFragement fragment = null;
fragment = new XYZFragement();
fragment.setPosition(position);
fragment.setSeatDetails(journeyDetailInfos.get(position).getPaxDetailsInfos());
fragment.setCountJourney(journeyDetailInfos.size());
frgaments.put(position,fragment);
return fragment;
}
#Override
public int getCount() {
return journeyDetailInfos.size();
}
And onCreateView of Fragment is
binding = DataBindingUtil.inflate(inflater, R.layout.layout_name, container, false);
binding.paxWithSeatList.setLayoutManager(new LinearLayoutManager(this.getContext()));
binding.setSeatPax(viewModel);
viewModel.setPassengers(seatDetails);
return binding.getRoot();
Problem is when the data list "journeyDetailInfos" has count of 2 the Fragment shows a data of second item of data list "journeyDetailInfos". It works smooth if the count is more than 2 While I tried with all possible solution discussed in issue nothing worked for me.
Try FragmentPagerAdapter instead of FragmentStatePagerAdapter and Override getItemId to update pager smoothly.
SeatJourneyAdapter.java
private class SeatJourneyAdapter extends FragmentPagerAdapter {
final SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public SeatJourneyAdapter() {
super(getChildFragmentManager());
}
#Override
public Fragment getItem(final int pos) {
XYZFragement fragment = null;
fragment = new XYZFragement();
fragment.setPosition(position);
fragment.setSeatDetails(journeyDetailInfos.get(position).getPaxDetailsInfos());
fragment.setCountJourney(journeyDetailInfos.size());
frgaments.put(position,fragment);
return fragment;
}
/**
* Implementing this method is IMPORTANT for detorying the fragment.
* Use unique id for each item on pagerData.
*/
#Override
public long getItemId(int position) {
return journeyDetailInfos.get(position).getId(); // Unique id by position and pager data.
}
#NonNull
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
#Override
public int getCount() {
return journeyDetailInfos.size();
}
}
Related
I have an Activity that have two Fragments and those fragments are presented to user by a ViewPager. So, I created a class extends FragmentStatePagerAdapter for ViewPager's adapter (MainFragsAdapter class) and I overrided some methods of it. I want to get my fragment's instances in my ViewPager from host Activity and get current fragment's root View by getView() method.
I got the instances of fragments by typing followings in Activity's onCreate() But getView() of that instance returns null :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainFragsAdapter = new MainFragsAdapter(getSupportFragmentManager());
viewPager = (ViewPager)findViewById(R.id.Pager);
viewPager.setAdapter(mainFragsAdapter);
int index = viewPager.getCurrentItem();
if(index == 0) {
Fragment1 fragment = (Fragment1)viewPager.getAdapter().instantiateItem(viewPager, index);
View v = fragment.getView();
Log.e("Frag1View",v.toString()); //At this point, I'm getting NullPointerException
//because getView() returns null.(Fragment isn't null)
}else if(index == 1){
Fragment2 fragment =(Fragment2)viewPager.getAdapter().instantiateItem(viewPager, index);
}
}
My FragmentStatePagerAdapter :
public class MainFragsAdapter extends FragmentStatePagerAdapter {
private SparseArray<Fragment> fragments = new SparseArray<>();
private Fragment currentFragment;
private int NUM_ITEMS = 2;
public MainFragsAdapter(FragmentManager fm,Context context) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
if(position == 0){
this.currentFragment = Fragment1.createInstance();
}
if(position == 1){
this.currentFragment =Fragment2.createInstance();
}
return this.currentFragment;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment)super.instantiateItem(container,position);
fragments.put(position,fragment);
return fragment; }
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
fragments.remove(position);
super.destroyItem(container,position,object);
}
public Fragment getRegisteredFragment(int position) {
return fragments.get(position);
}
}
How can i solve this issue ? Thank you for helps.
Here's the inner class that contains fragments and changes fragment views on swipe. This class is defined in an Activity.
private class ViewPagerAdapter extends FragmentPagerAdapter {
private int count;
ViewPagerAdapter(FragmentManager fm, int count) {
super(fm);
this.count = count;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new FriendsListFragment();
case 1:
Bundle bundle = new Bundle();
bundle.putString(Keys.TAG, ChatListFragment.class.getSimpleName());
ChatListFragment chatListFragment = new ChatListFragment();
chatListFragment.setArguments(bundle);
return chatListFragment;
case 2:
return new MoreFragment();
default:
return null;
}
}
#Override
public int getCount() {
return count;
}
}
Here I would like to add a code that sets tags to each fragment, so that I can recognize which fragment I'm at.
I searched quite much, and I haven't found a proper answer for this question, so please help.
You can override the setPrimaryItem method of your FragmentPagerAdapter.
private class ViewPagerAdapter extends FragmentPagerAdapter {
protected int currentPosition = -1;
protected Fragment currentFragment;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// ....
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
this.currentPosition = position;
if (object instanceof Fragment) {
this.currentFragment = (Fragment) object;
}
}
public int getCurrentPosition() {
return currentPosition;
}
public Fragment getCurrentFragment() {
return currentFragment;
}
}
Just use getCurrentPosition or getCurrentFragment methods to get information about current Fragment.
I want to update container fragment base on data inside the page fragment in ViewPager. I used this solution Retrieve a Fragment from a ViewPager and it works fine when I swipe the view.
But I cannot figure out how to get hint (callback) if first page is loaded. At the beginning? Of course onPageSelected is called but when I try to get fragment I got null.
Data data = null;
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
#Override
public void onPageSelected(int position) {
PageFragment page = MyPagerAdapter.getPageFragment(position);
if(page != null)
data = page.getData();
else
Log.w(TAG,"page is null"); //i get it at first time. :(
}
});
Below MyPageAdapter which I use (accordint to Retrieve a Fragment from a ViewPager)
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<PageFragment> registeredFragments = new SparseArray<PageFragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return ...;
}
#Override
public Fragment getItem(int position) {
return PageFragment.newInstance(...);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public PageFragment getPageFragment(int position) {
return registeredFragments.get(position);
}
}
I need to hide the second tab on particular condition, I have tried in following way, Tab hided, and text also changed, but fragment didn't changed, I mean, If I hided the second tab then I am getting FragmentStep2[second tab's content] on third tab,
public class PagerAdapter extends FragmentPagerAdapter {
private static final String TAG = "PagerAdapter";
private final String[] TITLES_WITH_STEP2 = {"step1", "step2", "step3", "step4"};
private final String[] TITLES_WITHOUT_STEP2 = {"step1", "step3", "step4"};
private ArrayList<Fragment> fragmentsList;
private boolean isShowStep2Tab = true;
public PagerAdapter(FragmentManager fm) {
super(fm);
fragmentsList = new ArrayList<>();
fragmentsList.add(new FragmentStep1());
fragmentsList.add(new FragmentStep2());
fragmentsList.add(new FragmentStep3());
fragmentsList.add(new FragmentStep4());
}
#Override
public CharSequence getPageTitle(int position) {
Log.v(TAG, "getPageTitle isShowStep2Tab : " + isShowStep2Tab);
fragmentsList = new ArrayList<>();
return isShowStep2Tab ? TITLES_WITH_STEP2[position] : TITLES_WITHOUT_STEP2[position];
}
#Override
public Fragment getItem(int position) {
/*Log.v(TAG, "getItem isShowStep2Tab : " + isShowStep2Tab);
if (getPageTitle(position).equals("Step1")) {
return new FragmentStep1();
} else if (getPageTitle(position).equals("Step2")) {
return new FragmentStep2();
} else if (getPageTitle(position).equals("Step3")) {
return new FragmentStep3();
} else if (getPageTitle(position).equals("Step4")) {
return new FragmentStep4();
}else {
return new FragmentStep4();
}*/
return fragmentsList.get(position);
}
#Override
public int getCount() {
Log.v(TAG, "getCount isShowStep2Tab : " + isShowStep2Tab);
fragmentsList = new ArrayList<>();
return isShowStep2Tab ? TITLES_WITH_STEP2.length : TITLES_WITHOUT_STEP2.length;
}
public void setShowFamilyTab(boolean isShowStep2Tab) {
this.isShowStep2Tab = isShowStep2Tab;
fragmentsList = new ArrayList<>();
if (isShowStep2Tab) {
fragmentsList.add(new FragmentStep1());
fragmentsList.add(new FragmentStep2());
fragmentsList.add(new FragmentStep3());
fragmentsList.add(new FragmentStep4());
} else {
fragmentsList.add(new FragmentStep1());
fragmentsList.add(new FragmentStep3());
fragmentsList.add(new FragmentStep4());
}
notifyDataSetChanged();
}
}
I don't know what is the problem here.
I would suggest you to pass only position to the getItem method of the adapter.
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i); // Our object is just an integer :-P
fragment.setArguments(args);
return fragment;
}
After that, you could get the position from your list of objects ( your pages) and check for condition (to show or not to show).
in your DemoObjectFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
FragmentPageToShow tempFragmentPage = fragmentDataList.get(args.getInt(ARG_OBJECT));
Use the same list of objects when you create the fragment page adapter.
public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i); // Our object is just an integer :-P
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// For this contrived example, we have a 100-object collection.
return fragmentDataList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentDataList.get(position).name;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}
Do not create FragmentStepX classes for each page. Just use one Fragment and pass data appropriately.
Either create array list of your data objects initially only for 'objects to show' or refresh your adapter dynamically whenever your array list changes.
You could always have the list of items to show before setting/refreshing the adapter.
I have a an activity in which i am setting a viewPager adapter as shown below
public class ViewPagerAdapter extends FragmentPagerAdapter {
private int pagerLength;
private HashMap<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
String page = "Page";
public ViewPagerAdapter(FragmentManager fm, int numPage) {
super(fm);
mFragmentManager = fm;
pagerLength = numPage;
mFragmentTags = new HashMap<Integer, String>();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if(obj instanceof Fragment) {
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
#Override
public Fragment getItem(int index) {
ImageFragment imageFragment = (ImageFragment)Fragment.instantiate(ImageActivity.this, imageFragment.class.getName(), null);
return imageFragment;
}
#Override
public int getCount() {
return pagerLength;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null) {
return (Fragment)instantiateItem(mViewPager, position);
}
Fragment fragment = mFragmentManager.findFragmentByTag(tag);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
mFragmentTags.remove(position);
super.destroyItem(container, position, object);
}
#Override
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return "TESTING"; //Remove later
}
}
ImageFragment is nothing spl its just a fragment with an imageView in its layout
Now I want to set a image in the imageView of the fragment from activity how am I supposed to do that?
I tried making a fn update in my activity and passing the imageUrl to a function called update in fragment. The problem is that although the update() in fragment gets called and receives the url of image, the onCreateView() of the fragment is never invoked