如何恢复先前显示的Fragment?

10

我在项目中使用兼容性包v4,并且在将Fragment从视图中移除后,保留它时出现了问题。我的Activity显示了两个片段,一个是左侧的菜单框架,一个是右侧的内容面板。左侧的菜单框架有3个不同的菜单(片段)可以显示。

这是我替换菜单Fragment的方式:

public void showMenuFragment( Fragment fragment, String tag ) {

        showFragment( R.id.menu_frame, fragment, tag, false);
        setLastMenuPushed( tag );
    }

protected void showFragment( int resId, Fragment fragment, String tag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( fragmentManager.findFragmentByTag( tag ) != null && fragment.isAdded() ) {
            transaction.remove( fragment );
        }

        transaction.replace( resId, fragment, tag ).setTransition( FragmentTransaction.TRANSIT_FRAGMENT_OPEN ).setBreadCrumbShortTitle( tag );

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();
    }
菜单“Fragment”需要在显示前加载数据,因此我显示了一个加载指示器。一旦第一次加载完成,我希望无需再次加载它,除非“Activity”已完成。
当我调用“showMenuFragment(...)”时,我尝试使用“FragmentManager.findFragmentByTag(String tag)”传递“Fragment”,但它始终为null,因此每次要显示不同的菜单时都必须创建新的“Fragment”。
我的问题是,如何在其他菜单替换它们后保留这些“Fragment”? 我想避免手动引用“Fragment”,因为在设备旋转时,我的“Activity”类的实例会被销毁,并且我将失去这些引用。
编辑:更简单地说,我希望“FragmentManager”在不必添加到后退堆栈的情况下跟踪以前的“Fragment”。 我不希望单击后退按钮并看到之前显示的菜单。
2个回答

15

我刚刚想到了解决方法。不是在添加新片段时将它们删除,而是隐藏它们,然后在需要显示它们时再显示出来。这是我的修改后的方法:

public void showMenuFragment( Fragment fragment, String tag, boolean addToBackStack ) {

        showFragment( R.id.menu_frame, fragment, tag, getLastMenuPushed(), addToBackStack );
        setLastMenuPushed( tag );
}

protected void showFragment( int resId, Fragment fragment, String tag, String lastTag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( lastTag != null ) {
            Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
            if ( lastFragment != null ) {
                transaction.hide( lastFragment );
            }
        }

        if ( fragment.isAdded() ) {
            transaction.show( fragment );
        }
        else {
            transaction.add( resId, fragment, tag ).setBreadCrumbShortTitle( tag );
        }

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();
}

3
回顾这件事,我认为更好的解决方案是将Fragment与Activity“分离”,并在类中保持对它的硬引用。 - Jason Robinson
分离(detach)和隐藏(hide)的优势是什么?销毁视图是否有真正的区别?您有没有好的方法在不重新加载整个片段的情况下恢复它? - ben
@ben Detach会将视图层次结构从屏幕上移除,这是一种更环保的方法。大多数视图在从Fragment中移除时都能很好地保存它们的实例状态,因此当重新附加时我不认为会有什么大问题。 - Jason Robinson
附加、分离调用需要API等级13,是否有其他替代方法? - madan V
2
实际上,“detach() 旧的 - add() 新的” 和 replace() 做的事情是一样的,即使用一个空的实例状态 Bundle 重新启动 Fragment 的生命周期,所以这并没有什么帮助。 - ugo

0
我不确定这是否可能。 FragmentManager 仅处理其 BackStack 上的 Fragments。但是,如果您让您的 FragmentActivity 实现 onBackButtonPressed 并让自定义行为发生,则可以解决后退按钮按下的问题。您可以将它们委托给您的 Fragments,或者根据您的应用逻辑显示另一个 Fragment

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接