Android:保持Fragment运行

igo*_*jrr 6 android android-fragments

是否有可能保持一个片段一边跑一边叫我replaceFragmentManager打开一个新的片段?

基本上我不想在导航(通过replace方法)到另一个片段时暂停片段.

可能吗?或者正确的方法是,每当我需要打开它并恢复其先前的状态时,总是会实例化一个新的片段?

谢谢!

Rez*_*adi 11

FragmentManger replace方法将完全破坏前一个片段,因此在每个事务onDestroyView(),onDestroy()和onDetach()都将在前一个片段上调用.如果你想保持你的片段运行,你可以使用FragmentManger hide()和show()方法!它隐藏并显示碎片而不破坏它们.

所以首先将两个片段添加到片段管理器中,并隐藏第二个片段.

        fragmentManager.beginTransaction()
            .add(R.id.new_card_container, FragmentA)
            .add(R.id.new_card_container,FragmentB)
            .hide(FragmentB)
            .commit();
Run Code Online (Sandbox Code Playgroud)

请注意,您只能在隐藏片段上调用show().所以在这里你不能在FragmentA上调用show(),但这不是问题,因为通过隐藏和显示FragmentB你可以获得你想要的替换效果.

这是一种在片段之间来回切换的方法.

public void showOtherFragment() {

    if(FragmentB.isHidden()){
        fragmentManager.beginTransaction()
                .show(FragmentB).commit();

    } else {
        fragmentManager.beginTransaction()
                .hide(FragmentB).commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将日志消息放入片段回调方法中,您将看到没有破坏(除了屏幕方向更改!),甚至视图也不会被破坏,因为onDistroyView没有被调用.

只有一个问题就是,第一次应用程序启动onCreateView()方法时会为每个片段调用一次(它应该是!)但是当方向更改onCreateView()时会为每个片段调用两次,这是因为片段一旦像往常一样创建,一次因为FragmentManger的附件(保存在bundle对象上)为了避免你有两个选项1)在onSaveInstaneState()回调中分离片段.

@Override
protected void onSaveInstanceState(Bundle outState) {
    fragmentManager.beginTransaction()
            .detach(FragmentA)
            .detach(FragmentB)
            .commit();

    super.onSaveInstanceState(outState);
}
Run Code Online (Sandbox Code Playgroud)

它正在工作,但视图状态不会自动更新,例如,如果您有一个EditText,其文本将在每次方向更改发生时擦除.当然,您可以通过在片段中保存状态来解决这个问题,但如果使用第二个选项则不需要!

首先,我在onSaveInstaneState()方法中保存一个布尔值,以记住巫婆片段.

@Override
protected void onSaveInstanceState(Bundle outState) {
    boolean isFragAVisible = true;
    if(!FragmentB.isHidden())
        isFragAVisible = false;

    outState.putBoolean("isFragAVisible",isFragAVisible);

    super.onSaveInstanceState(outState);
}
Run Code Online (Sandbox Code Playgroud)

现在在活动onCreate方法我检查以查看savedInstanceState == null.如果是,那么如果没有活动是第二次创建的话.所以片段管理器已经包含了片段.所以我得到了片段管理器中我的片段的引用.我也确保显示正确的片段,因为它没有自动恢复.

    fragmentManager = getFragmentManager();

    if(savedInstanceState == null){

        FragmentA = new FragmentA();
        FragmentB = new FragmentB();
        fragmentManager.beginTransaction()
                .add(R.id.new_card_container, FragmentA, "fragA")
                .add(R.id.new_card_container, FragmentB, "fragB")
                .hide(FragmentB)
                .commit();

    } else {
        FragmentA = (FragmentA) fragmentManager.findFragmentByTag("fragA");
        FragmentB = (FragmentB) fragmentManager.findFragmentByTag("fragB");

        boolean isFragAVisible = savedInstanceState.getBoolean("isFragAVisible");
        if(isFragAVisible)
            fragmentManager.beginTransaction()
                    .hide(FragmentB)
                    .commit();
        else
            fragmentManager.beginTransaction()
                    .hide(FragmetA) //only if using transaction animation
                    .commit();
    }
Run Code Online (Sandbox Code Playgroud)

到目前为止,如果不使用事务动画,您的片段将完美运行.如果这样做,您还需要显示和隐藏FragmentA.因此,当你想显示FragmentB时,首先隐藏FragmentA然后显示FragmentB(在同一个事务中),当你想要隐藏FragmentB时首先隐藏它并同时显示FragmentA(再次在同一个事务中).这是我的卡片翻转动画代码(从developer.goodle.com下载)

public void flipCard(String direction) {
    int animationEnter, animationLeave;
    if(direction == "left"){
        animationEnter = R.animator.card_flip_right_in;
        animationLeave = R.animator.card_flip_right_out;
    } else {
        animationEnter = R.animator.card_flip_left_in;
        animationLeave = R.animator.card_flip_left_out;
    }

    if(cardBack.isHidden()){
        fragmentManager.beginTransaction()
                .setCustomAnimations(animationEnter, animationLeave)
                .hide(cardFront)
                .show(cardBack)
                .commit();

    } else {
        fragmentManager.beginTransaction()
                .setCustomAnimations(animationEnter,animationLeave)
                .hide(cardBack)
                .show(cardFront)
                .commit();
    }
}
Run Code Online (Sandbox Code Playgroud)