Android SupportFragmentManager,popbackstack&;屏幕旋转
我有一个让我发疯的奇怪问题 场景:Android SupportFragmentManager,popbackstack&;屏幕旋转,android,android-fragments,Android,Android Fragments,我有一个让我发疯的奇怪问题 场景: @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen for landscape and portrait if (newConfig.orientat
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen for landscape and portrait
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager()
.getBackStackEntryAt(0).getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE));
} else {
super.onBackPressed();
}
}
我有活动
A作为启动器活动
和活动
B可以通过活动A中的意图
启动
Activity A --> Activity B
活动B有一个初始的片段
称之为片段
C,它在活动
B中实例化,如下所示:
if(getSupportFragmentManager().findFragmentByTag(FragmentC.TAG) == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container,
FragmentC.newInstance(null), // optional bundle
FragmentC.TAG)
.commit();
}
在Fragment
C中,我在ViewHolder上有一个OnClickListener
的RecyclerView
,它通过Fragment
C调用宿主活动B。此时,我启动FragmentTransaction
(在Activity
B中)要替换当前的Fragment
C,请将其称为Fragment
D,我将此事务添加到backstack:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.anim.fragment_slide_enter,
R.anim.fragment_slide_exit,
R.anim.fragment_slide_enter_pop,
R.anim.fragment_slide_exit_pop)
.replace(R.id.container,
FragmentD.newInstance(bundle),
FragmentD.TAG)
.addToBackStack(null)
.commit();
因此,在这一点上,我有活动B和Fragment
D,事务从Fragment
C到Fragment
D在后堆栈中,像这样处理后压:
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
从开始Activity
A到Activity
B-->Fragment
D再到后面,导航可以正确地向前和向后运行
问题:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen for landscape and portrait
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager()
.getBackStackEntryAt(0).getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE));
} else {
super.onBackPressed();
}
}
但是,如果我在Fragment
D中并旋转屏幕,然后pop
返回到Fragment
C(撤消事务),我会看到一个空白的Fragment
。更奇怪的是,所有Fragment
C的生命周期方法OnCreate()
,OnCreateView()
,OnActivityCreated()
都被调用,并且我拥有有效的数据/对象(通过设置断点进行检查)
然而,奇怪的是,如果我在从Fragment
C-->Fragment
D执行add
事务,显然这两个都会同时显示在彼此的顶部,我旋转屏幕,按下后退键并删除事务,那么没有问题,显然不是解决方案,只是观察
我已经搜索过了,但我读过和尝试过的一切都不起作用。我以前也实现过类似的东西,效果很好,但我在这里很挣扎-任何帮助都将不胜感激
编辑
如果应用程序进入暂停状态(单独运行,屏幕关闭),然后再次唤醒并继续运行,则片段将按其应有的方式显示。我在恢复时没有初始化,所以我不知道为什么会这样。您的问题是由于屏幕旋转造成的
根据文档,每次设备配置更改时(如用户旋转屏幕时),您的活动都将被销毁并重新创建。当屏幕更改方向时,系统将销毁并重新创建前台活动,因为屏幕配置已更改,并且您的活动可能需要加载其他资源(如布局)
在这种情况下,活动B再次启动初始框架C,所有生命周期方法再次执行
解决方案
您可以在纵向模式下限制您的活动
您应该在片段中处理onConfigurationChanged()
方法,并定义setRetainInstance(true))
公共void setRetainInstance(布尔保留)
控制是否在活动重新创建期间保留片段实例(例如从配置更改)。这只能用于不在后堆栈中的片段。如果设置,则重新创建活动时片段生命周期将略有不同:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen for landscape and portrait
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager()
.getBackStackEntryAt(0).getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE));
} else {
super.onBackPressed();
}
}
我以前也遇到过同样的问题。我已经提出了满足我要求的解决方案
在活动B的menifest中使用以下代码
android:configChanges="keyboardHidden|orientation|screenSize"
上面的行不允许破坏您的活动,因此您没有碎片破坏问题问题已解决
好的,谢谢你的建议,但我已经自己解决了这个问题
解决方案是什么?很简单,我踢自己
在弹出backbackback时,我从未将片段的getId()
包含到“pop”中:
之前的代码依赖于FragmentActivity
在onBackPressed()中弹出backbackbackback本身。事实上,文件和方法应注意以下事项:
/**
* Take care of popping the fragment back stack or finishing the activity
* as appropriate.
*/
@Override
public void onBackPressed() {
if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
super.onBackPressed();
}
}
但是,当发生配置更改并且您希望弹出前一事务的backbackback时,这似乎无法正常工作。代码解决方案是自己手动“弹出”后堆栈:
之前:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen for landscape and portrait
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager()
.getBackStackEntryAt(0).getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE));
} else {
super.onBackPressed();
}
}
之后(工作解决方案):
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen for landscape and portrait
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager()
.getBackStackEntryAt(0).getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE));
} else {
super.onBackPressed();
}
}
getId()
的文档说明:
/**
* Return the unique identifier for the entry. This is the only
* representation of the entry that will persist across activity
* instances.
*/
public int getId();
因此,基本上,在发生配置更改(托管活动
已被销毁并重新创建)后,成功“弹出”backbackback的唯一方法是引用片段
唯一的id单个片段
并托管活动
处理配置更改 适当-此解决方案不适用于我遇到的问题。单个片段
和托管活动
处理配置更改 对于活动,您可以在清单文件中定义Configchanges属性。对于fragment,您可以重写onConfigurationChanged()方法,就像我在解决方案中解释的那样,如果您面临problem@NishchalAndroid这是有道理的。我观察到,对于片段,一旦生命周期方法按原样调用,则在旋转屏幕时调用onCreate()
和onestroy()
而不调用onResume()
和onPause()
。记录生命周期方法并亲自查看@MarkKeen@Rolbin我已经检查过了(我提到了破po