Fragment系列(三)

来源:互联网 发布:深圳海思 知乎 编辑:程序博客网 时间:2024/06/06 06:45

使用Fragment一些建议

封装BaseFragment基类

例如为了实例化View,抽象一个getLayoutId方法,子类无需关心具体的创建操作,父类来做View的创建处理。同时可以提供一个afterCreate抽象函数,在初始化完成之后调用,子类可以做一些初始化的操作,你也可以添加一些常用的方法在基类,例如ShowToast().

 public abstract class BaseFragment extends Fragment {protected View mRootView;@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {if(null == mRootView){   mRootView = inflater.inflate(getLayoutId(), container, false);}return mRootView;}@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);afterCreate(savedInstanceState);}protected abstract int getLayoutId();protected abstract void afterCreate(Bundle savedInstanceState);}

使用newInstance(参数) 创建Fragment对象

调用者只需要关心传递的哪些数据,而无需关心传递数据的Key是什么。

public static WeatherFragment newInstance(String cityName) {Bundle args = new Bundle();args.putString(cityName,"cityName");WeatherFragment fragment = new WeatherFragment();fragment.setArguments(args);return fragment;}

Fragment推荐使用setArguments来传递参数,避免在横竖屏切换的时候Fragment自动调用自己的无参构造函数,导致数据丢失。

使用Activity全局变量

如果在Fragment要使用宿主Activity,建议在Fragment中定义一个全局变量,在onAttach中初始化,这不是最好的解决办法,但这可以有效避免一些意外Crash,通常由于getActivity()返回null。

protected Activity mActivity;@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);this.mActivity = activity;}

不要在Fragment里面保存ViewState

为了让你的代码更加清晰和稳定,最好区分清楚fragment状态保存和view状态保存,如果某个属性属于View,则不要在Fragment中做它的状态保存,除非属性属于Fragment。每一个自定义View都有义务实现状态的保存,可以像EditText一样,设置一个开关来选择是否保存
比如说:android:freezeText=”true/false”。

add()、show()、hide()、replace()使用建议

区别:

show()、hide()是让Fragment中的view setVisibility true or false(即显示还是隐藏),不会调用到Fragment的生命周期函数;

replace()会销毁视图,即调用onDestoryView、onCreateView等一系列生命周期

add()和 replace()不要在同一个阶级的FragmentManager里混搭使用。

使用场景:

如果你频繁使用当前Fragment,建议使用show()、hide();

如果你的app有大量图片,建议使用replace(),因为销毁时能够回收其图片所占用的内存;

onHiddenChanged的回调时机:

当使用add()+show(),hide()跳转新的Fragment时,旧的Fragment回调onHiddenChanged(),不会回调onStop()等生命周期方法,而新的Fragment在创建时是不会回调onHiddenChanged(),这点要切记。

Fragment重叠问题:

使用show(),hide()带来的一个问题就是,如果你不做任何额外处理,在“内存重启”后,Fragment会重叠;(该BUG在support-v4 24.0.0+以上 官方已修复)

Fragment里监听虚拟按键和实体按键的返回事件

给rootView设置一个OnKeyListener来监听key事件

mRootView.setFocusable(true);mRootView.setFocusableInTouchMode(true);mRootView.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {//不一定是要触发返回栈,可以做一些其他的事情,我只是举个栗子。getActivity().onBackPressed();return true;}return false;}});

使用FragmentManager注意点

FragmentManager是用来管理Fragment

FragmentManager栈视图:每个Fragment以及宿主Activity(继承自FragmentActivity)都会在创建时,初始化一个FragmentManager对象,处理好Fragment嵌套问题的关键,就是理清这些不同阶级的栈视图。
下面给出一个简要的关系图:

这里写图片描述

对于宿主Activity,getSupportFragmentManager()获取的FragmentActivity的FragmentManager对象;

对于Fragment,getFragmentManager()是获取的是父Fragment(如果没有,则是FragmentActivity)的FragmentManager对象,而getChildFragmentManager()是获取自己的FragmentManager对象。

使用FragmentPagerAdapter+ViewPager的注意事项

使用FragmentPagerAdapter+ViewPager时,切换回上一个Fragment页面时(已经初始化完毕),不会回调任何生命周期方法以及onHiddenChanged(),只有setUserVisibleHint(boolean isVisibleToUser)会被回调,所以如果你想进行一些懒加载,需要在这里处理。

在给ViewPager绑定FragmentPagerAdapter时,
new FragmentPagerAdapter(fragmentManager)的FragmentManager,一定要保证正确,如果ViewPager是Activity内的控件,则传递getSupportFragmentManager(),如果是Fragment的控件中,则应该传递getChildFragmentManager()。只要记住ViewPager内的Fragments是当前组件的子Fragment这个原则即可。

你不需要考虑在“内存重启”的情况下,去恢复的Fragments的问题,因为FragmentPagerAdapter已经帮我们处理啦。

是使用单Activity+多Fragment的架构,还是多模块Activity+多Fragment的架构?

单Activity+多Fragment:
一个app仅有一个Activity,界面皆是Frament,Activity作为app容器使用。
优点:性能高,速度最快。参考:新版知乎 、google系app

缺点:逻辑比较复杂,尤其当Fragment之间联动较多或者嵌套较深时,比较复杂。

多模块Activity+多Fragment:
一个模块用一个Activity,比如

1、登录注册流程:
LoginActivity + 登录Fragment + 注册Fragment + 填写信息Fragment + 忘记密码Fragment

2、或者常见的数据展示流程:
DataActivity + 数据列表Fragment + 数据详情Fragment + …

优点:速度快,相比较单Activity+多Fragment,更易维护。

建议:多模块Activity+多Fragment是最合适的架构

最后推荐一个作为参考的demo框架:Fragmentation 源码地址:Github

(第三篇到此结束)

0 0
原创粉丝点击