Android:使用1个活动的主/明细stream(双窗格)

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

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

我正在使用第一种情况 (Android指南只解释第二种情况)。

这是7“平板电脑上发生的事情:

  • 从横向旋转到纵向 :只有单窗格片段被重新创build
  • 从纵向旋转到横向 :所有3个片段(单窗格,双窗格主,双窗格细节)被重新创build

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

我在我的实施报告下面:

/layout/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(); } } 

Solutions Collecting From Web of "Android:使用1个活动的主/明细stream(双窗格)"

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

因此,而不是使用<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(); } 

使用这些function:

 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(); } 

旋转时,当前活动的片段将由FragmentManager保存,并在创build新Activity时用于自动重新创build片段。 您可以通过不将savedInstanceState传递给super方法来防止重新创build。 例如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(); }