FragmentManager的使用及管理

Fragment的产生与介绍

Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套app,然后拷贝一份,修改布局以适应什么超级大屏的。难道无法做到一个app可以同时适应手机和平板吗?答案是,当然有,那就是Fragment。Fragment出现的初衷就是为了解决这样的问题。

你可以把Fragment当成Activity一个界面的一部分,甚至Activity的界面由完全不同的Fragment组成,更帅气的是Fragment有自己的声明周期和接收、处理用户的事件,这样就不必要在一个Activity里面写一堆事件、控件的代码了。更为重要的是,你可以动态的添加、替换、移除某个Fragment。

Fragment的生命周期

Fragment必须是依存于Activity而存在的,因此Activity的生命周期会直接影响到Fragment的生命周期。官网这张图很好的说明了俩者的关系:
fragment_lifecycle

Fragment的使用及管理

基础的使用这里就不在说了,主要写一下开发中遇到的问题和经验。

1.获取当前的Fragment对象。

    public Fragment getCurrentFragment() {

        Fragment currentFragment = null;

        FragmentManager fragmentManager = getSupportFragmentManager();
        List fragments = fragmentManager.getFragments();
        if (null != fragments) {
            for (Fragment tmp : fragments) {
                if (tmp != null && tmp.isVisible()) {
                    currentFragment = tmp;
                }
            }
        }

        return currentFragment;
    }

2.当使用多个Fragment代替Activity时,需要控制返回键。因为默认情况下按返回,会退出Activity。

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction ft = fragmentManager.beginTransaction();
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.addToBackStack(null);
    ft.add(R.id.frame_content, new MyFragment());
    ft.commit();

重写Activity的退出方法。

    @Override
    public void onBackPressed() {

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.popBackStack();
    }

3.切换Fragment时保存数据

要想在切换Fragment时保存数据,需要防止Fragment重新实例化。

    public void switchContent(Fragment from, Fragment to) {
        if (mContent != to) {
            mContent = to;
            FragmentTransaction transaction = mFragmentMan.beginTransaction().setCustomAnimations(
                    android.R.anim.fade_in, R.anim.slide_out);
            if (!to.isAdded()) {    // 先判断是否被add过
                transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
            } else {
                transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
            }
        }
    }

注意:当使用Fragment代替Activity时,如果使用上面第二个方法,调用FragmentManager中的popBackStack(),那么FragmentManager会从堆栽中删除上一个Fragment,造成每次都会实例化。如:有一个Activity,有两个Fragment,分别为FA和FB。进入Activity时默认显示FA,然后操作时FA调用FB。这个时候若从FB按返回键回到FA,那么FA再次调用FB时会重新实例化。

如何避免以上问题呢?我是自己写了一些方法进行堆栽管理。


    private Stack fragmentStack;

    public void switchToFragment(int fragmentId, boolean pushStack) {

        Fragment currentFragment = getCurrentFragment();
        // 这是我自己写的一个方法,根据ID获取不同Fragment
        Fragment f = getFragment(fragmentId);

        FragmentTransaction ft = fragmentManager.beginTransaction();
        if (null != currentFragment) {
            ft.hide(currentFragment);
        }

        if (f.isAdded()) {
            ft.show(f);
        } else {
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.addToBackStack(null);
            ft.add(R.id.frame_content, f);
        }

        ft.commit();

        if (null == fragmentStack) {
            fragmentStack = new Stack();
        }
        if (pushStack) {
            fragmentStack.push(fragment);
        }
    }

    @Override
    public void onBackPressed() {

        fragmentStack.pop(); // 从栽弹出当前页面
        if (fragmentStack.isEmpty()) {
            finish();
        } else {
            int fragment = fragmentStack.peek();
            switchToFragment(fragment, false);
        }
    }

评论已关闭。