8

正如Android指南所报道的,双窗格可以通过两种方式实现:

  1. 多个片段,一个活动
  2. 多个片段,多个活动

我使用的是第一种情况(Android 指南只解释了第二种情况)。

这是7 英寸平板电脑上发生的情况:

  • 从横向旋转到纵向:仅重新创建单窗格片段
  • 从纵向旋转到横向:重新创建所有 3 个片段(单窗格、双窗格主、双窗格细节)

问题:为什么单窗格片段(我以编程方式创建,但使用布局中定义的 FrameLayout 作为容器)在双窗格上重新创建?

我在我的实施情况下报告:

/布局/activity_main.xml:

<FrameLayout
    android:id="@+id/single_pane"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

/layout-w900dp/activity_main.xml:

<LinearLayout
    android:id="@+id/dual_pane"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment class="com.example.MasterFragment"
        android:id="@+id/master_dual"
        android:tag="MASTER_FRAGMENT_DUAL_PANE"
        android:layout_width="@dimen/master_frag_width"
        android:layout_height="match_parent"/>
    <fragment class="com.example.DetailFragment"
        android:id="@+id/detail_dual"
        android:tag="DETAIL_FRAGMENT_DUAL_PANE"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

这是onCreate主要活动:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDualPane = findViewById(R.id.dual_pane)!=null;

    FragmentManager fm = getFragmentManager();
    if (savedInstanceState==null) {
        // this is a non-UI fragment I am using for data processing purposes
        fm.beginTransaction().add(new NonUiFragment(), DATA_FRAGMENT).commit();
    }
    if (!mDualPane && fm.findFragmentById(R.id.single_pane)==null) {
        fm.beginTransaction().add(R.id.single_pane, new MasterFragment(), MASTER_FRAGMENT_SINGLE_PANE).commit();
    }
}
4

2 回答 2

5

我发现在代码中为双窗格添加片段要好得多。

因此,不要使用<fragment>,也可以将<FrameLayout>也用于双窗格 XML。

/layout-w900dp/activity_main.xml:

<LinearLayout
    android:id="@+id/dual_pane"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/master_dual"
        android:layout_width="@dimen/master_frag_width"
        android:layout_height="match_parent"/>
    <FrameLayout
        android:id="@+id/detail_dual"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

这样,您可以只使用masterFragment 和 DetailFragment 的一个实例,因此您不会陷入同一片段的多个实例的问题。

为此,OnCreate您需要将片段添加到容器中,从旧容器中分离:

    mDualPane = findViewById(R.id.dual_pane)!=null;

    if (savedInstanceState!=null) {
        mLastSinglePaneFragment = savedInstanceState.getString("lastSinglePaneFragment");
    }

    FragmentManager fm = getSupportFragmentManager();

    if (!mDualPane && fm.findFragmentById(R.id.single_pane)==null) {
        MasterFragment masterFragment = getDetatchedMasterFragment(false);
        fm.beginTransaction().add(R.id.single_pane, masterFragment, MASTER_FRAGMENT).commit();
        if (mLastSinglePaneFragment==DETAIL_FRAGMENT) {
            openSinglePaneDetailFragment();
        }
    }
    if (mDualPane && fm.findFragmentById(R.id.master_dual)==null) {
        MasterFragment masterFragment = getDetatchedMasterFragment(true);
        fm.beginTransaction().add(R.id.master_dual, masterFragment, MASTER_FRAGMENT).commit();
    }
    if (mDualPane && fm.findFragmentById(R.id.detail_dual)==null) {
        DetailFragment detailFragment = getDetatchedDetailFragment();
        fm.beginTransaction().add(R.id.detail_dual, detailFragment, DETAIL_FRAGMENT).commit();
    }

使用这些功能:

public static final String MASTER_FRAGMENT = "MASTER_FRAGMENT";
public static final String DETAIL_FRAGMENT = "DETAIL_FRAGMENT";

private MasterFragment getDetatchedMasterFragment(boolean popBackStack) {
    FragmentManager fm = getSupportFragmentManager();
    MasterFragment masterFragment = getSupportFragmentManager().findFragmentByTag(MASTER_FRAGMENT);
    if (masterFragment == null) {
        masterFragment = new MasterFragment();
    } else {
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
        fm.beginTransaction().remove(masterFragment).commit();
        fm.executePendingTransactions();
    }
    return masterFragment;
}

private DetailFragment getDetatchedDetailFragment() {
    FragmentManager fm = getSupportFragmentManager();
    DetailFragment detailFragment = getSupportFragmentManager().findFragmentByTag(DETAIL_FRAGMENT);
    if (detailFragment == null) {
        detailFragment = new DetailFragment();
    } else {
        fm.beginTransaction().remove(detailFragment).commit();
        fm.executePendingTransactions();
    }
    return detailFragment;
}

private void openSinglePaneDetailFragment() {
    FragmentManager fm = getSupportFragmentManager();
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    DetailFragment detailFragment = getDetatchedDetailFragment();
    FragmentTransaction fragmentTransaction = fm.beginTransaction();
    fragmentTransaction.replace(R.id.single_pane, detailFragment, DETAIL_FRAGMENT);
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();
}
于 2015-05-17T14:36:25.943 回答
0

当你旋转时,FragmentManager 会保存当前处于活动状态的 Fragment,并用于在创建新 Activity 时自动重新创建 Fragment。您可以通过不将 savedInstanceState 传递给 super 方法来防止重新创建。例如super.onCreate(null);

或者,如果您需要使用 FragmentActivity.onCreate(savedInstanceState) 方法(调用 FragmentManager.restoreAllState() 来恢复状态 -请参阅https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/ FragmentManager.java#L1759),您可以在 onCreate 中查找您的片段标签并手动删除它。之所以如此,是因为您有一个要恢复的非 ui 片段。保留片段的恢复还取决于使用 saveInstanceState != null 调用 FragmentActivity.onCreate(savedInstanceState)。

重新创建是因为通常您希望保留活动片段(并且可能在平板电脑的情况下添加第二个详细信息窗格)。

if (mDualPane) {
    Fragment singlePane = getFragmentManager().findFragmen‌​tByTag(MASTER_FRAGMENT_SINGLE_PANE);
    if (singlePane != null)
        getFragmentManager().beginTransaction().remove(fragment).commit(); 
}
于 2014-08-21T17:32:12.200 回答