一直比较懒,没写过博文,近日打通了七经八脉,灵感突发,想想还是写写博文吧!记录一下项目中遇到的问题,水平一般,技术有限,不喜勿喷
简单介绍一下,我在项目中使用到了ViewPager + Fragment这个东东,这个东东在项目中用的却是挺多的,下面简单说说我遇到的问题。
问题一:Fragment 中嵌套Fragment 界面不显示问题
刚开始写Fragment俺是用下面这种写法写的
OneFragment mOneFragment = new OneFragment(); TwoFragment mTwoFragment = new TwoFragment(); ThreeFragment mThreeFragment = new ThreeFragment(); ArrayList
fragments = new ArrayList<>(); fragments.add(mOneFragment); fragments.add(mTwoFragment); fragments.add(mThreeFragment); //给viewPager添加适配器,分配Fragment mViewPager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
哎呦喂,噫吁唏,它不显示,这就有点不地道了,回头一想这在之前在Activity+ViewPager+Fragment用的明明是可以的呀,我就开始怀疑人生,以为是我人品出了问题,回家之后开始诵读论语,哎呦扯远了远了。。。重新修炼人品之后这样写
OneFragment mOneFragment = new OneFragment(); TwoFragment mTwoFragment = new TwoFragment(); ThreeFragment mThreeFragment = new ThreeFragment(); ArrayList
fragments = new ArrayList<>(); fragments.add(mOneFragment); fragments.add(mTwoFragment); fragments.add(mThreeFragment); //给viewPager添加适配器,分配Fragment mViewPager.setAdapter(new MyFragmentPagerAdapter(getChildFragmentManager(), fragments));
高兴呼,,,,,可以哉,,,,,到此发现真Low
下面聊聊getSupportFragmentManager()和getChildFragmentManager() 的不同吧,慢着,聊他俩之前呢得先说getFragmentManger()
1.getFragmentManger()是Activity中的方法,是在Activity中管理Fragment的,人家是这样说滴
/** * Return the FragmentManager for interacting with fragments associated * with this activity. */ public FragmentManager getFragmentManager() { return mFragments.getFragmentManager(); }
俺们是这样说滴:返回一个管理Activity中Fragments的管理者也就 是FragmentManager,管理者(小伙子还是当官的,厉害)那么如何管理呢???????????
FragmentManager是通过事物来管理Fragment的,也就是这哥们Transaction
这哥们是这样来的
开启事物之后,可以添加、替换、隐藏、显示、移除Fragment,可以从Activity中分离和绑定,最后就是提交事物,方法如下:FragmentManager manager = getFragmentManager(); FragmentTransaction fragmentTransaction = manager.beginTransaction();//开启事物
以上就是 FragmentManager对Fragment的管理操作fragmentTransaction.add(fragment,tag);//添加 fragmentTransaction.replace(containerViewId,fragment,ag);//替换 fragmentTransaction.hide(fragment);//隐藏 fragmentTransaction.show(fragment);//显示 fragmentTransaction.remove(fragment);//移除 fragmentTransaction.detach(fragment);//分离 fragmentTransaction.attach(fragment);//绑定 fragmentTransaction.commit();//提交
下面来说说 getSupportFragmentManager()2.getSupportFragmentManager()是FragmentActivity中的方法,在V4包中提供,所以在使用getSupportFragmentManager()时要将自己的Activity继承于FragmentActivity
getFragmentManger()和getSupportFragmentManager()的区别是:前者主要用于Android3.0以上,后者主要用于Android3.0一下,因为Fragment是Android3.0出来的,所以要在3.0以下使用Fragment就要添加V4依赖包
其管理Fragment的方法和以上一样
下面再来看看getChildFragmentManager()
3.getChildFragmentManager()是Fragment中提供的方法,用来在Fragment中管理Fragment
所以问题中的不显示问题就是这样引起的
问题二:ViewPager + Fragment 预加载问题使用过ViewPager的小伙伴们都知道,它是有预加载功能的,默认的预加载页面为三个,也就是当前页面、左边一个界面
右边一个界面。为什么会有预加载呢,是为了左右滑动是更加流畅,给用户带来更好的用户体验 但是在使用时就会遇到这样一个问题,在Fragment中有网络请求时就会同时促发,造成数据的冗余,并且不安全。
这只是其中一个问题,因为有预加载就要将预加载的Fragment初始化,所以有关Fragment初始化的操作都会执行
那么如何解决这个问题,我想到了两种方式,一种就是屏蔽ViewPager的预加载,另一种就是每当Fragment可见的时候才去请求网络
1.屏蔽ViewPager的预加载功能
在ViewPager的源码中有这样一个静态final成员变量
这个哥们默认为1,要将其设置为0,就可以屏蔽预加载了那么怎么设置呢?????private static final int DEFAULT_OFFSCREEN_PAGES = 1;
不能通过viewpager.setOffscreenPageLimit(limit);这个方法设置预加载页面的数量,如果limit小于1的话设置是 无效的,默认还是为1.那么就需要该源码了,怎么改,当然不能直接该,源码都是禁止写的,那就将V4包中的ViewPager
复制出来一份,将复制出来的ViewPager中的DEFAULT_OFFSCREEN_PAGES改为0,让后再将修改好的复制到V4包中,替换
掉原来的ViewPager,OK!!!!但是这样不好,用户体验差,每次都要新建Fragment,不流畅,我是用第二种方法解决问题的2.在Fragment 中有一个这样的方法setUserVisibleHint(),当Fragment可见或者不可见时被调用此方法的执行是在Fragment之前调用的,所以在使用时要注意不能直接将可见或者不可见的逻辑放在此方法中执行会报空指针异常可以这样处理: 在基类中public abstract class BaseFragment extends Fragment { protected boolean isVisible; /** * 在这里实现Fragment数据的缓加载. * * @param isVisibleToUser */ @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (getUserVisibleHint()) { isVisible = true; onVisible(); } else { isVisible = false; onInvisible(); } } protected void onVisible() { lazyLoad(); } /**
protected void lazyLoad() {* 子类在此方法中做懒加载逻辑 */
} protected void onInvisible() { }
}
在子类中
以上我的业务需求当界面可见时不断接收广播,接收到广播后去请求数据public class OneFragment extends BaseFragment { //用来标识当前界面是否加载完成 private boolean isPrepared; @Override public void OnActCreate(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { isPrepared = true; lazyLoad(); } BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { getNet(); } }; @Override protected void lazyLoad() { if(!isPrepared || !isVisible) { return; } IntentFilter filter = new IntentFilter(); filter.addAction("UPDATE_NET"); mContext.registerReceiver(receiver, filter); getNet(); } @Override public void onDestroyView() { super.onDestroyView(); isVisible = false; onInvisible(); } @Override protected void onInvisible() { if(!isVisible&&isPrepared){ try { mContext.unregisterReceiver(receiver); }catch (Exception e){ } } } }
这样就处理了预加载问题