这正是我面临的问题。我的解决方案并没有阻止viewpager创建片段,但它会停止对网络api的调用。
要点如下:
1) 创建接口
public interface ViewPagerLifeCycleManagerInterface {
void onResumeAndShowFragment();
void onPauseAndHideFragment();
//void refreshFragment();
}
2) 修改FragmentPagerAdapter以覆盖OnInstallateItem方法
这里,每个片段将在适配器类中声明一个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);
}
}
}
其他片段的接口方法相同。
这很复杂,但确实有效。适配器内部的弱引用甚至允许垃圾收集并避免上下文泄漏。