停止FragmentPagerAdapter一次创建所有片段

时间:2018-04-15 09:39:04

标签: java android android-fragments android-viewpager android-adapter

所以我有一个底部导航栏,每个标签有4个片段,在每个标签里面我调用一个API请求来获取一些数据,但问题是每次我按下栏的任何标签,至少有两个片段得到了创建,他们调用自己的方法,并通过扩展他们激活API请求..!我只想要实例化我选择的片段。!

我知道适配器的行为类似于预渲染片段以确保标签之间更好的交易等等。但我真的无法承担每次选择多个API呼叫..!

适配器

public class My_PagerAdapter extends FragmentPagerAdapter {
                       // I've tried FragmentStatePagerAdapter but same thing

  public My_PagerAdapter (FragmentManager fm) {
    super(fm);
  }

  @Override
  public Fragment getItem(int position) {

    switch (position) {
      case 0:
         new MyFragment_1();
      case 1:
         new MyFragment_2();
      case 2:
         new MyFragment_3();
      case 3:
         new MyFragment_4();
    }

  }

  @Override
  public int getCount() {
    return 4;
  }
}

修改

这是我如何调用适配器..

ViewPager viewPager = main.findViewById(R.id.vp); 
viewPager.setOffscreenPageLimit(1); 
viewPager.setAdapter(new My_PagerAdapter (getChildFragmentManager()));
navigationTabBar.setModels(models); // just UI stuff for each tab offered by the bottom navigation bar library, 
navigationTabBar.setViewPager(viewPager);

2 个答案:

答案 0 :(得分:2)

我在一个正在从事的项目中遇到了同样的问题

对我来说,解决方案是在每个片段的OnResume方法上添加API调用。 这样,只有在片段完全可见时才会触发它们。

签出fragment lifecycle

答案 1 :(得分:1)

好的,这正是我面临的一个问题。我所拥有的解决方案并没有阻止viewpager创建片段,但它将停止对网络api的调用。

继承人的要点:

1)创建一个界面

public interface ViewPagerLifeCycleManagerInterface {
  void onResumeAndShowFragment();
  void onPauseAndHideFragment();
  //void refreshFragment();
}

2)修改FragmentPagerAdapter以覆盖onInstantiantiItem方法

这里每个Fragment都会在Adapter类中声明一个weakReference,以便存储对创建的片段的引用

    @Override
public Object instantiateItem(ViewGroup container, int position){

    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);

    switch (position){
        case 0:
            xyzWeakReference=null;
            xyzFragmentWeakReference=new WeakReference<>((xyz)createdFragment);
            break;

        case 1:
            xyz1WeakReference=null;
            xyz1WeakReference=new WeakReference<>((xyz1WeakReference)createdFragment);
            break;

    }

    return createdFragment;
};

3)在FragmentPagerAdapter中,添加以下方法以获取图片中片段的弱引用

    public Fragment getFragmentAtGivenPosition(int i){
    switch (i){
        case 0:
            if(xyzFragmentWeakReference == null){
                return null;
            }
            return xyzFragmentWeakReference.get();
        case 1:
            if(xyz1FragmentWeakReference == null){
                return null;
            }
            return xyz1FragmentWeakReference.get();

    }
}

4)现在,在创建TabLayout并实例化视图寻呼机的活动中,将一个监听器附加到TabLayout以监听标签更改

        tabLayout_bookmarks.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(final TabLayout.Tab tab) {
            //let the instantiateItem have some time to be called by the adapter

            currentFragmentIndex = tab.getPosition();

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {

                    ViewPagerLifeCycleManagerInterface currentFragment = (ViewPagerLifeCycleManagerInterface)btca.getFragmentAtGivenPosition(tab.getPosition());

                    if(currentFragment!=null){
                        currentFragment.onResumeAndShowFragment();
                    }else{
                        //Log.d("FragmentCreate","Current fragment is null and fucked up in adapter");

                        //if it is null ... that means the adapter hasn't yet called instantiate item ... this internally calls get item any way
                        //.....

                        //This shouldn't really hit but in case it does ... keep a handler in order to ensure that everything is created
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                ViewPagerLifeCycleManagerInterface localFragment  = (ViewPagerLifeCycleManagerInterface)btca.getItem(tab.getPosition());
                                //getItem never returns a null fragment unless supplied a horrendous value for position
                                //by the time these 50 ms pass, the instantiate item should surely have been called
                                //else it will be an empty space ... no crash though
                                localFragment.onResumeAndShowFragment();
                            }
                        },50);
                    }

                }
            },100);

        }

        @Override
        public void onTabUnselected(final TabLayout.Tab tab) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    ViewPagerLifeCycleManagerInterface currentFragment = (ViewPagerLifeCycleManagerInterface)btca.getFragmentAtGivenPosition(tab.getPosition());
                    if(currentFragment!=null){
                        currentFragment.onPauseAndHideFragment();
                    }else{
                        //Log.d("FragmentCreateTab","the fucking fragment was null");
                        //if it is null ... that means the adapter hasn't yet called instantiate item ... this internally calls get item any way
                        //.....

                        //This shouldn't really hit but in case it does ... keep a handler in order to ensure that everything is created
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                ViewPagerLifeCycleManagerInterface localFragment  = (ViewPagerLifeCycleManagerInterface)btca.getItem(tab.getPosition());
                                //getItem never returns a null fragment unless supplied a horrendous value for position
                                //by the time these 50 ms pass, the instantiate item should surely have been called
                                //else it will be an empty space ... no crash though
                                localFragment.onPauseAndHideFragment();
                            }
                        },50);

                    }

                }
            },100);
        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            //do nothing
        }
    });

5)在Viewpager内的每个片段中,实现我们在步骤1中创建的接口并覆盖方法。

在每个片段中创建一个布尔变量amIVisible ...这将有助于确定片段何时可​​见以及何时可以调用网络api

a)这里是viewpager中的第一个片段,即在0索引处,网络api调用必须在创建视图后立即发生。默认情况下,此片段显然是可见的。这是写在onCreateView方法

        if(dataList!=null && dataList.size()==0) {
        if (savedInstanceState==null) {
            //your api call to load from net
        } else {
            if (savedInstanceState.getBoolean("savedState")) {
                //If you have saved data in state save, load it here
            } else {
                //only fire the async if the current fragment is the one visible, else the onResumeAndShowFragment will trigger the same async when it becomes visible
                if (savedInstanceState.getBoolean("amIVisible")) {
                    //Load data from net
                }
            }
        }
    }

第一个片段的其他方法如下

    @Override
public void onResumeAndShowFragment() {
    amIVisible=true;


    if(dataList!=null && dataList.size()==0){
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Load data from net if data was not found,
                //This basically means auto refresh when user scrolls back and the fragment had no data
            }
        },400);
    }
}

@Override
public void onPauseAndHideFragment() {
    amIVisible=false;
}

这里我重写了onSaveInstanceState方法并保存了amIVisible的值,savedState是一个布尔值,表示列表是否至少有1个项目。

b)对于其他片段,数据将通过以下过程加载

        if(savedInstance!=null){

        if (savedInstance.getBoolean("savedState")) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                   //load data from saved State
                }
            },100);

        } else {
            //only fire the async if the current fragment is the one visible, else the onResumeAndShowFragment will trigger the same async when it becomes visible


            if (savedInstance.getBoolean("amIVisible")) {

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //load data from net
                    }
                },100);

            }
        }
    }

其他片段的接口方法相同。

这很复杂,但是做得很好。适配器中的弱引用甚至允许垃圾收集并避免上下文泄漏。