有一些类似的答案,但不是这种情况。
我的情况很简单。
我有一个具有两种不同布局的活动,一个在Portrait中,另一个在Landscape中。
在肖像中,我使用<FrameLayout>
并在其中添加Fragment
动态。
在横向中,我使用<fragment>
,因此Fragment
静态。 (事实上这没关系)
首先以人像开头,然后我简单地添加了Fragment
:
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
其中ListFrag extends ListFragment
。
然后我做一个屏幕旋转。 我发现listFrag正在横向模式下重新创建。
(其中我注意到onCreate()
方法再次使用非空Bundle调用)
我尝试使用setRetainInstance(false)
像@NPike在this post中说的那样。但默认情况下getRetainInstance()
已经false
。它没有按照the docs所说的那样做。有人可以解释一下吗?
我正在处理的片段是ListFragment
,它在setListAdapter()
中onCreate()
。所以if (container == null) return null;
method不能在这里使用。 (或者我不知道如何申请)。
我从this post得到了一些提示。我应该在if (bundle != null) setListAdapter(null); else setListAdapter(new ...);
中使用ListFragment
吗?但是,当它被销毁/分离时,是否有更好的方法来删除/删除片段,而不是在创建时间内执行它? (以及if (container == null) return null;
方法)
修改
我找到的唯一简洁方法是在getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit();
中执行onSaveInstanceState()
。但它会引发另一个问题。
当屏幕被部分遮挡时,会弹出WhatsApp或TXT对话框,片段也会消失。 (这是相对较小的,只是视觉问题)
当屏幕旋转时,活动将被完全销毁并重新创建。所以我可以在onCreate(Bundle)
或onRestoreInstanceState(Bundle)
中重新添加片段。但是在(1)的情况下,以及切换活动时,当用户返回我的Activity时,都不会调用onCreate(Bundle)
和onRestoreInstanceState(Bundle)
。我无处可重新创建活动(并从Bundle中检索数据)。
对不起,我没有说清楚,我已做出决定,getSupportFragmentManager()...replace(...).commit();
行仅在肖像模式下运行。
我已经提取了简单的代码,以便更好地说明情况:)
MainActivity.java
package com.example.fragremovetrial;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.FragmentContainer) != null) {
System.out.println("-- Portrait --"); // Portrait
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
} else {
System.out.println("-- Landscape --"); // Landscape
}
}
@Override
protected void onResume() {
super.onResume();
if (findViewById(R.id.FragmentContainer) != null) {
System.out.println("getRetainInstance = " +
getSupportFragmentManager().findFragmentById(R.id.FragmentContainer).getRetainInstance());
}
}
}
布局/ activity_main.xml中
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/FragmentContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
layout-land / activity_main.xml (无所谓)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
ListFrag.java
package com.example.fragremovetrial;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;
public class ListFrag extends ListFragment {
private String[] MenuItems = { "Content A", "Contnet B" };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("ListFrag.onCreate(): " + (savedInstanceState == null ? null : savedInstanceState));
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, MenuItems));
}
}
注意我得到了以下
- 肖像 -
ListFrag.onCreate():null
getRetainInstance = false
(旋转端口 - &gt; Land)
ListFrag.onCreate():Bundle [{android:view_state=android.util.SparseArray@4052dd28}]
- 风景 -
以前专注的视图在保存期间报告了ID 16908298,但在恢复期间无法找到
(旋转陆地 - >端口)
ListFrag.onCreate():Bundle [{android:view_state=android.util.SparseArray@405166c8}]
- 肖像 -
ListFrag.onCreate():null
getRetainInstance = false
(旋转端口 - &gt; Land)
ListFrag.onCreate():Bundle [{android:view_state=android.util.SparseArray@4050fb40}]
- 风景 -
以前专注的视图在保存期间报告了ID 16908298,但在恢复期间无法找到
(旋转陆地 - >端口)
ListFrag.onCreate():Bundle [{android:view_state=android.util.SparseArray@40528c60}]
- 肖像 -
ListFrag.onCreate():null
getRetainInstance = false
当屏幕保持旋转时,创建的片段数量将不无限增加,这是我无法解释的。 (请帮忙)
答案 0 :(得分:2)
我终于提出了一个解决方案,以防止在重新创建活动时重新创建不需要的Fragment。这就像我在问题中提到的那样:
我找到的唯一简洁方法是在
getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit();
中执行onSaveInstanceState()
。但它会引发另一个问题......
......有一些改进。
在onSaveInstanceState()
:
@Override
protected void onSaveInstanceState(Bundle outState) {
if (isPortrait2Landscape()) {
remove_fragments();
}
super.onSaveInstanceState(outState);
}
private boolean isPortrait2Landscape() {
return isDevicePortrait() && (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
和isDevicePortrait()
就像:
private boolean isDevicePortrait() {
return (findViewById(R.id.A_View_Only_In_Portrait) != null);
}
*请注意,我们 无法 使用getResources().getConfiguration().orientation
来确定设备当前是字面纵向。这是因为Resources
对象在屏幕旋转后更改 RIGHT AFTER - 以前 {{ 1}}被称为!!
如果我们不想使用onSaveInstanceState()
来测试方向(出于任何原因,并且它不是那么整洁),请保留一个全局变量findViewById()
并将其初始化为private int current_orientation;
in current_orientation = getResources().getConfiguration().orientation;
。这似乎更整洁。但我们应该注意 不要 在活动生命周期中的任何地方进行更改。
*确保我们onCreate()
之前 remove_fragments()
。
(因为在我的情况下,我从布局和活动中删除碎片。如果它在super.onSaveInstanceState()
之后,布局将已经保存到Bundle中。然后碎片将<在活动重新创建后重新创建strong> 。###)
###我已经证明了这一现象。但What to determine a Fragment restore upon Activity re-create?的原因仅仅是我的猜测。如果您对此有任何想法,请回答my another question。
答案 1 :(得分:1)
处理此问题的正确方法是将以下内容放在onCreate()
中if (savedInstanceState == null) {
// Do fragment transaction.
}
答案 2 :(得分:0)
在onCreate()
方法中,如果您处于纵向模式,则只应创建ListFrag
。您可以通过检查纵向布局中仅包含的FrameLayout视图是否为null
来执行此操作。
if (findViewById(R.id.yourFrameLayout) != null) {
// you are in portrait mode
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
} else {
// you are in landscape mode
// get your Fragment from the xml
}
最后,如果您从纵向布局切换到横向布局,则不希望创建另一个ListFrag,而是使用您在xml中指定的片段。
答案 3 :(得分:0)
@midnite,首先感谢你的问题,我有同样的问题,我工作了几天。现在我对这个问题做了一些棘手的解决 - 并希望与社区分享这个问题。 但如果有人有更好的解决方案,请写下评论。
所以,我有相同的情况 - 两个设备方向的不同布局。在肖像中,不需要DetailsFragment。
我只是在OnCreate中试图找到已创建的片段:
fragment = (ToDoListFragment) getFragmentManager().findFragmentByTag(LISTFRAGMENT);
frameDetailsFragment = (FrameLayout) findViewById(R.id.detailsFragment);
detailsFragment = (DetailsFragment) getFragmentManager().findFragmentByTag(DETAILS_FRAGMENT);
settingsFragment = (SettingsFragment) getFragmentManager().findFragmentByTag(SETTINGS_FRAGMENT);
之后我正在添加我的主要片段 -
if (fragment == null){
fragment = new ToDoListFragment();
getFragmentManager().beginTransaction()
.add(R.id.container, fragment, LISTFRAGMENT)
.commit();
}
然后清除我的碎片:
if (getFragmentManager().getBackStackEntryCount() > 0 ) {
getFragmentManager().popBackStackImmediate();
}
最有趣的是 -
destroyTmpFragments();
这是方法本身:
private void destroyTmpFragments(){
if (detailsFragment != null && !detailsFragment.isVisible()) {
Log.d("ANT", "detailsFragment != null, Destroying");
getFragmentManager().beginTransaction()
.remove(detailsFragment)
.commit();
detailsFragment = null;
}
if (settingsFragment != null && !settingsFragment.isVisible()) {
Log.d("ANT", "settingsFragment != null, Destroying");
getFragmentManager().beginTransaction()
.remove(settingsFragment)
.commit();
settingsFragment = null;
}
}
如你所见,我手动清理FragmentManager为我保存的所有碎片(非常感谢他)。 在日志中,我有下一个生命周期调用:
04-24 23:03:27.164 3204 3204 D ANT MainActivity onCreate()
04-24 23:03:27.184 3204 3204 I ANT DetailsFragment :: onCreateView
04-24 23:03:27.204 3204 3204 I ANT DetailsFragment :: onActivityCreated
04-24 23:03:27.204 3204 3204 I ANT DetailsFragment :: onDestroy
04-24 23:03:27.208 3204 3204 I ANT DetailsFragment :: onDetach
因此在onActivityCreated中,您的视图会检查null - 以防片段不可见。它稍后会被删除(也许是因为cuz片段管理器的删除是异步的) 之后,在活动代码中,我们可以创建全新的Fragment实例,并使用适当的布局(fargmnet&#39;占位符),片段将能够找到它的视图,并且不会产生NullPointerException < / p>
但是,后备堆栈中的片段会被删除得相当快,而无需调用onActivityCreated(借助上述代码:
if (getFragmentManager().getBackStackEntryCount() > 0 ) {
getFragmentManager().popBackStackImmediate();
}
最后,如果我在陆地方向,最后我会添加片段 -
if (frameDetailsFragment != null){
Log.i("ANT", "frameDetailsFragment != null");
if (EntryPool.getPool().getEntries().size() > 0) {
if (detailsFragment == null) {
detailsFragment = DetailsFragment.newInstance(EntryPool.getPool().getEntries().get(0), 0);
}
getFragmentManager().beginTransaction()
.replace(R.id.detailsFragment, detailsFragment, DETAILS_FRAGMENT)
.commit();
}
}