Activity & Fragment & tips

来源:互联网 发布:知乎怎么发不了文章 编辑:程序博客网 时间:2024/06/06 16:34

相比于Activity来说,创建一个Fragment所需系统资源相比Activity来说更少,然而控制却更为灵活。Fragment一般分为两类,一类是有UI的Fragment,可以作为页面,作为View来展示,另一类是用没有UI的Fragment,一般用作保存数据。

封装BaseFragment基类

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

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

public View onCreateView 这个方法中返回之前判断一下你的mRootView是null再inflate,这样会比较好,在ViewPager中随着页面滑动这个方法会调用多次,inflate过了之后就直接用就好了。

使用静态工厂方法newInstance(…)来获取Fragment实例

可以在Google的代码中发现这种写法,好处是接收确切的参数,返回一个Fragment实例,避免了在创建Fragment的时候无法在类外部知道所需参数的问题,在合作开发的时候特别有用。
还有就是Fragment推荐使用setArguments来传递参数,避免在横竖屏切换的时候Fragment自动调用自己的无参构造函数,导致数据丢失。

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

Fragment状态保存/现场恢复

不要在Fragment里面保存ViewState!
为了让你的代码更加清晰和稳定,最好区分清楚fragment状态保存和view状态保存,
如果某个属性属于View,则不要在Fragment中做它的状态保存,除非属性属于Fragment。

每一个自定义View都有义务实现状态的保存,可以像EditText一样,设置一个开关来选择是否保存
比如说:android:freezeText=”true/false”。

public class CustomView extends View {    @Override    public Parcelable onSaveInstanceState() {        Bundle bundle = new Bundle();        // 在这里保存当前状态        return bundle;    }    @Override    public void onRestoreInstanceState(Parcelable state) {        super.onRestoreInstanceState(state);        // 恢复保存的状态    }}

处理fragment状态保存,例如保存从服务器获取的数据。

private String serverData;    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        outState.putString("data", serverData);    }    @Override    public void onActivityCreated(Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        serverData = savedInstanceState.getString("data");    }

避免错误操作导致Fragment的视图重叠

视图重叠是因为fragment已经发生了内存泄漏。
activity的创建、销毁完全托管到systemserver(ams),而fragment一般是手动new一个对象再add到systemserver,所以这里就有问题了。
fragment生命周期开始于add,结束于remove。不管app中间怎么变化,崩溃、进程被回收,只要没有remove,android框架都会自动创建、恢复fragment的状态。
这个问题很简单,在add或者replace的时候,调用含有TAG参数的那个方法,之后再add相同TAG的Fragment的话,之前的会被替换掉,也就不会同时出现多个相同的Fragment了。

public class WeatherFragment extends Fragment {    //TAG    public static final String TAG = WeatherFragment.class.getSimpleName();

不过为了最大限度的重用,可以在Activity的onCreate(Bundle savedInstanceState)中判断savedInstanceState是否不为空;

不为空的话,先用getSupportFragmentManager(). findFragmentByTag()找一下,找到实例就不用再次创建。

WeatherFragment fragment = null;if(savedInstanceState!=null){fragment = getSupportFragmentManager().findFragmentByTag(WeatherFragment.TAG);}if(fragment == null){   fragment = WeatherFragment.newInstance(...);}

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

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

注意事项:
* FragmentTransaction异步执行相关问题。FragmentTransaction#commit函数是异步执行的(其把本次transaction的所有操作添加到消息队列里),不注意这一点可能会出现一些奇怪的问题。比如闪屏问题:view的显示隐藏是同步执行的,而fragment的hide、show是异步执行的,所以可能会碰到view隐藏了,而fragment的界面还没显示,导致闪屏。不过android也提供了FragmentManager#executePendingTransactions方法,强制同步执行。

0 0