Reputation: 2687
I have a FragmentStatePagerAdapter with 6 fragments inside.
Each Fragment connect's to the server and loads data.
Right now, the server connection is being done in Fragment.onStart(), that means that at any moment, I have 3 http requests going (the selected Fragment, and one to each side).
What I want is to have only one connection at the time, so I figure to use
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
@Override
public void onPageSelected(final int position)
{
CustomFragment fragment = (CustomFragment) myFragmentStatePagerAdapter.getItem(position);
fragment.onSelected();//do stuff in here
}
});
The thing is, getItem()
returns a new instance of the fragment, not yet added to the manager (and thus, not yet view created, etc).
Also, I've tried setUserVisibleHint(boolean isVisibleToUser)
but is not being call on visible, only on isVisibleToUser = false
So, how to achieve a "onPageSelected()" event for the Fragment?
Thanks in advance
Upvotes: 6
Views: 9283
Reputation: 1862
Late to the train .Personally none of this approach is my favorite . They are hacky. Best way is using Adapters setPrimaryItem(ViewGroup container, int position, Object object)
Inside setPrimaryItem' save the current Fragment and use it inside
onPageSelected(final int position)`
Code sample goes some thing like this ,
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
currentFragment = (ProductListFragment) object;
}
// Inside view pager listener use the currently visible fragment
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
@Override
public void onPageSelected(final int position)
{
currentFragment.onSelected(); // do your thing man
}
});
Upvotes: 1
Reputation: 2792
In your FragmentStatePagerAdapter
use a HashMap
to hold the created Fragments, then you can
access them later from your viewpager container (activity or fragment):
public class CustomFragmentPagerAdapter extends FragmentStatePagerAdapter {
private HashMap<Integer, CustomFragment> fragMap =
new HashMap<Integer, CustomFragment>();
...
@Override
public Fragment getItem(int position) {
CustomFragment frag = new CustomFragment();
...
fragMap.put(position, frag);
return frag;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
fragMap.remove(position);
}
public CustomFragment getFragment(int position) {
return fragMap.get(position);
}
...
}
Now, in your viewpager container(activity or fragment):
private int lastPage = 0;
...
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
CustomFragment fragment;
int currentPage = viewPager.getCurrentItem();
/* connect the current fragment and disconnect the previous one, in case
you actually need to disconnect it from the server,
otherwise just connect the current fragment.*/
if(currentPage > lastPage) {
fragment = yourPagerAdapter.getFragment(currentPage - 1);
fragment.disconnect();
fragment = yourPagerAdapter.getFragment(currentPage);
fragment.connect();
} else {
fragment = yourPagerAdapter.getFragment(currentPage + 1);
fragment.disconnect();
fragment = yourPagerAdapter.getFragment(currentPage);
fragment.connect();
}
lastPage = currentPage;
}
});
Since the onPageChangeListener is not called when the app is started, you will need to connect the first fragment. The important thing is that you will have a reference to the fragments returned by getItem()
using yourPagerAdapter.getFragment(currentPage)
.
Edit:
I think this may be a better logic for onPageSelected()
callback method:
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
CustomFragment fragment;
int currentPage = viewPager.getCurrentItem();
Set<Integer> myKeySet = yourPagerAdapter.getKeys();
for(Integer key : myKeySet) {
if(key == currentPage) {
fragment = yourPagerAdapter.getFragment(key);
fragment.connect();
} else {
fragment = yourPagerAdapter.getFragment(key);
fragment.disconnect();
}
}
}
});
But you need to implement this methd on FragmentStatePagerAdapter
:
public Set<Integer> getKeys() {
return fragMap.keySet();
}
and get rid of lastPage
data member.
Upvotes: 0
Reputation: 3000
What has worked for me is, in my pager adapter's getItem
method, to save in a list my own reference to the custom fragment I return. The contract that both fragment pager adapter and fragment state pager adapter seem to follow means that the last fragment returned by getItem(i)
will be the correct fragment to refresh in the onPageSelected(i)
method.
I have only tested this technique with a fragment pager adapter and a reasonably small number of tabs. With a state pager adapter some testing would be needed to see if holding references to fragments causes memory use to increase.
Upvotes: 1
Reputation: 20406
The best solution for you would be to override setUserVisibleHint()
. Make sure you extend FragmentPagerAdapter
. From its source code you can see it calls setUserVisibleHint(true)
for visible fragments too. I use it all the time and it works well.
// adapter
public static class PlayerAdapter extends FragmentStatePagerAdapter {
public PlayerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 6;
}
@Override
public Fragment getItem(int position) {
return new SimpleFragment();
}
}
// fragment
public class SimpleFragment extends Fragment {
private static final String TAG = BookControlsFragment.class.getSimpleName();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_simple, container, false);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Log.d(TAG, "setUserVisibleHint: " + isVisibleToUser);
}
}
Upvotes: 8