FragmentStatePagerAdapter onPageSelected事件

时间:2014-05-25 16:05:21

标签: android android-fragments android-viewpager

我有一个FragmentStatePagerAdapter,里面有6个片段。

每个Fragment连接到服务器并加载数据。

现在,服务器连接正在Fragment.onStart()中完成,这意味着在任何时候,我都会有3个http请求(选定的片段,每边一个)。

我想要的是当时只有一个连接,所以我打算使用

 viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
 { 
    @Override
    public void onPageSelected(final int position)
    {
        CustomFragment fragment = (CustomFragment) myFragmentStatePagerAdapter.getItem(position);

        fragment.onSelected();//do stuff in here
    }
 });

问题是,getItem()返回片段的新实例,尚未添加到管理器中(因此,尚未创建视图等)。

另外,我已经尝试了setUserVisibleHint(boolean isVisibleToUser)但是没有看到可见,只有isVisibleToUser = false

那么,如何为Fragment实现“onPageSelected()”事件?

提前致谢

4 个答案:

答案 0 :(得分:8)

最适合您的解决方案是覆盖setUserVisibleHint()。确保延长FragmentPagerAdapter。从source code开始,您可以看到它也会调用setUserVisibleHint(true)来查看可见的片段。我一直都在使用它,效果很好。

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

答案 1 :(得分:1)

对我来说有用的是,在我的寻呼机适配器的getItem方法中,我将自己对我返回的自定义片段的引用保存在列表中。片段寻呼机适配器和片段状态寻呼机适配器似乎遵循的合同意味着getItem(i)返回的最后一个片段将是在onPageSelected(i)方法中刷新的正确片段。

我只使用片段寻呼机适配器和相当少数量的标签测试了这种技术。使用状态寻呼机适配器,需要进行一些测试,以查看对片段的引用是否会导致内存使用增加。

答案 2 :(得分:0)

FragmentStatePagerAdapter使用HashMap来保存创建的片段,然后就可以了 稍后从viewpager容器(活动或片段)访问它们:

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

现在,在viewpager容器(活动或片段)中:

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

由于在启动应用程序时未调用onPageChangeListener,因此您需要连接第一个片段。重要的是,您将使用getItem()引用yourPagerAdapter.getFragment(currentPage)返回的片段。

修改

我认为这可能是onPageSelected()回调方法的更好逻辑:

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

        }
    });

但是你需要在FragmentStatePagerAdapter

上实现这个方法
public Set<Integer> getKeys() {
    return fragMap.keySet();
} 

并删除lastPage数据成员。

答案 3 :(得分:0)

火车晚了。从根本上说,这种方法都不是我最喜欢的。他们很hacky。最好的方法是使用适配器setPrimaryItem(ViewGroup container, int position, Object object)

on setPrimaryItem' save the current Fragment and use it inside onPageSelected(final int position)`

代码示例有点像这样,

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