片段返回堆栈和切换
Fragment backstack and toggle
我有一个特殊的用例,我需要在两个片段之间切换。我遇到的问题是,对于第二个片段,我需要保持它的状态,而唯一似乎为此工作的是将它添加到 BackStack。
我依赖支持片段管理器来替换片段:
public void toggle() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceof FragmentB && null != fragmentA) {
// fragment B is visible - we should show fragment A
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out,
R.anim.frag_fade_in, R.anim.frag_fade_out)
.replace(R.id.fragment_container, fragmentA)
.commit();
} else if (fragment instanceof FragmentA && null != fragmentB) {
// fragment A is visible - we should show fragment B
boolean isRestored = false;
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentB = (FragmentB) fragment;
isRestored = true;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in,
R.anim.frag_fade_out,
R.anim.frag_fade_in,
R.anim.frag_fade_out);
transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B);
if(!isRestored){
transaction.addToBackStack(TAG_FRAG_B)
}
transaction.commit();
} else {
// Just pop any fragments that were added - usually we won't get in here
getSupportFragmentManager().popBackStack();
}
}
这与 onBackPressed() 覆盖相结合:
@Override
public void onBackPressed() {
if (isCurrentFragmentB()) {
toggle();
} else {
// Back key was pressed and we are on fragment A - at this state we simply want to go back to the
// previous section
super.onBackPressed();
}
}
使用这个实现,我确保我重用片段 B 并保持它的状态,这样它看起来不像每次都是从头开始创建的。我还确保当我返回时,我只能从片段 B 到 A 而不能从片段 A 到 B。
我遇到的问题是,当调用 super.onBackPressed();
并且通过片段管理器添加了多个片段(实际上已替换,因为我一次只想要一个活动片段)时,它会抛出一个异常:
java.lang.IllegalStateException: Fragment already added: FragmentA{af9c26b #0 id=0x7f0e00d3}
只有当活动片段是 FragmentA 时才会发生这种情况。我怀疑这是因为 BackStack 的实现,但正如我所说,我只希望保留第二个。
我该如何解决这个问题?我错过了什么?
我已经设法为此实施了一个变通办法,尽管它有点老套。
因为我需要保持FragmentB的状态,我不得不将它添加到BackStack中,但这实际上会影响调用onBackPressed()时反转的转换。
为了避免这种情况,我不得不更新后按的逻辑并手动处理这种情况
@Override
public void onBackPressed() {
if (isCurrentFragmentB()) {
toggle();
} else if (isCurrentFragmentA()) {
getSupportFragmentManager().popBackStackImmediate(TAG_FRAG_A, FragmentManager.POP_BACK_STACK_INCLUSIVE);
// Special case - because we added the fragment B to the BackStack in order to easily resume it's state,
// this will fail as it will actually try to add fragment A again to the fragment manager (it
// will try to reverse the last transaction)
super.finish();
} else {
// Usual flow - let the OS decide what to do
super.onBackPressed();
}
}
此外,我对切换方法进行了一些优化:
public void toggle() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
@SuppressLint("CommitTransaction") FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out,
R.anim.frag_fade_in, R.anim.frag_fade_out);
if (fragment instanceof FragmentB && null != fragmentA) {
// fragment B is visible - we should show fragment A
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_A);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentA = (FragmentA) fragment;
}
// Replace current fragment with fragment A and commit the transaction
transaction.replace(R.id.fragment_container, fragmentA, TAG_FRAG_A).commit();
} else if (fragment instanceof FragmentA && null != fragmentB) {
// fragment A is visible - we should show fragment B
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentB = (FragmentB) fragment;
}
// Replace current fragment with fragment B
transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B);
if (null == fragment) {
// No entry of the fragment B in the BackStack, we want to add it for future uses
transaction.addToBackStack(TAG_FRAG_B);
}
// Commit the transaction
transaction.commit();
} else {
// Just pop any fragments that were added - usually we won't get in here
getSupportFragmentManager().popBackStack();
}
}
我希望这可以帮助其他需要类似流程的人。
PS:我想要保留的片段是 SupportMapFragment
,这样我的地图就不会总是在每次我想显示它时重新绘制、重新居中并填充数据。
我有一个特殊的用例,我需要在两个片段之间切换。我遇到的问题是,对于第二个片段,我需要保持它的状态,而唯一似乎为此工作的是将它添加到 BackStack。
我依赖支持片段管理器来替换片段:
public void toggle() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceof FragmentB && null != fragmentA) {
// fragment B is visible - we should show fragment A
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out,
R.anim.frag_fade_in, R.anim.frag_fade_out)
.replace(R.id.fragment_container, fragmentA)
.commit();
} else if (fragment instanceof FragmentA && null != fragmentB) {
// fragment A is visible - we should show fragment B
boolean isRestored = false;
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentB = (FragmentB) fragment;
isRestored = true;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in,
R.anim.frag_fade_out,
R.anim.frag_fade_in,
R.anim.frag_fade_out);
transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B);
if(!isRestored){
transaction.addToBackStack(TAG_FRAG_B)
}
transaction.commit();
} else {
// Just pop any fragments that were added - usually we won't get in here
getSupportFragmentManager().popBackStack();
}
}
这与 onBackPressed() 覆盖相结合:
@Override
public void onBackPressed() {
if (isCurrentFragmentB()) {
toggle();
} else {
// Back key was pressed and we are on fragment A - at this state we simply want to go back to the
// previous section
super.onBackPressed();
}
}
使用这个实现,我确保我重用片段 B 并保持它的状态,这样它看起来不像每次都是从头开始创建的。我还确保当我返回时,我只能从片段 B 到 A 而不能从片段 A 到 B。
我遇到的问题是,当调用 super.onBackPressed();
并且通过片段管理器添加了多个片段(实际上已替换,因为我一次只想要一个活动片段)时,它会抛出一个异常:
java.lang.IllegalStateException: Fragment already added: FragmentA{af9c26b #0 id=0x7f0e00d3}
只有当活动片段是 FragmentA 时才会发生这种情况。我怀疑这是因为 BackStack 的实现,但正如我所说,我只希望保留第二个。
我该如何解决这个问题?我错过了什么?
我已经设法为此实施了一个变通办法,尽管它有点老套。
因为我需要保持FragmentB的状态,我不得不将它添加到BackStack中,但这实际上会影响调用onBackPressed()时反转的转换。
为了避免这种情况,我不得不更新后按的逻辑并手动处理这种情况
@Override
public void onBackPressed() {
if (isCurrentFragmentB()) {
toggle();
} else if (isCurrentFragmentA()) {
getSupportFragmentManager().popBackStackImmediate(TAG_FRAG_A, FragmentManager.POP_BACK_STACK_INCLUSIVE);
// Special case - because we added the fragment B to the BackStack in order to easily resume it's state,
// this will fail as it will actually try to add fragment A again to the fragment manager (it
// will try to reverse the last transaction)
super.finish();
} else {
// Usual flow - let the OS decide what to do
super.onBackPressed();
}
}
此外,我对切换方法进行了一些优化:
public void toggle() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
@SuppressLint("CommitTransaction") FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.frag_fade_in, R.anim.frag_fade_out,
R.anim.frag_fade_in, R.anim.frag_fade_out);
if (fragment instanceof FragmentB && null != fragmentA) {
// fragment B is visible - we should show fragment A
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_A);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentA = (FragmentA) fragment;
}
// Replace current fragment with fragment A and commit the transaction
transaction.replace(R.id.fragment_container, fragmentA, TAG_FRAG_A).commit();
} else if (fragment instanceof FragmentA && null != fragmentB) {
// fragment A is visible - we should show fragment B
fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_B);
if (null != fragment) {
// Restore fragment state from the BackStack
fragmentB = (FragmentB) fragment;
}
// Replace current fragment with fragment B
transaction.replace(R.id.fragment_container, fragmentB, TAG_FRAG_B);
if (null == fragment) {
// No entry of the fragment B in the BackStack, we want to add it for future uses
transaction.addToBackStack(TAG_FRAG_B);
}
// Commit the transaction
transaction.commit();
} else {
// Just pop any fragments that were added - usually we won't get in here
getSupportFragmentManager().popBackStack();
}
}
我希望这可以帮助其他需要类似流程的人。
PS:我想要保留的片段是 SupportMapFragment
,这样我的地图就不会总是在每次我想显示它时重新绘制、重新居中并填充数据。