FragmentStatePagerAdapter onPageSelected event

匿名 (未验证) 提交于 2019-12-03 01:33:01

问题:

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

回答1:

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);     } } 


回答2:

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.



回答3:

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 fragMap =          new HashMap();      ...      @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 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 getKeys() {     return fragMap.keySet(); }  

and get rid of lastPage data member.



回答4:

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 insideonPageSelected(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       }   }); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!