Android 同时使用 getFragmentManager 和 getSupportFragmentManager 导致重叠
Android using both getFragmentManager and getSupportFragmentManager causes overlapping
我的 activity:
里有这样的东西
@Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 2: {
SwipeRefreshListFragment swipeFragment = new Fragment_List_Of_Assessments();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, swipeFragment)
.commit();
break;
}
case 3: {
fragment = new Fragment_Report();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 4: {
fragment = new Fragment_Settings();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
default:
break;
}
}
The program automatically loads case1, but when case2 is selected, getSupportFragmentManager loads the Fragment on top of case1.我想同时使用 supportFragmentManager 和 FragmentManager 有一些问题。他们似乎有自己的堆栈。问题是我不能只使用其中一个,因为 SwipeToRefresh Android 示例使用需要支持的 ListView。v4.Fragment 需要旧的 FragmentManager。那么如何将两个 FragmentManagers 集成在一起呢?
我在使用 PreferenceFragment(支持库版本不支持)时完成了类似的事情。为了实现这一点,我在 Activity 中保留了一对布尔值(isLastFragmentSupportType
和 lastFragmentShowed
)以及一个字符串(lastFragmentTag
)。
一开始你的 Activity 会让它们都为 false。当你添加一个新的 Fragment 时,你使用这两个布尔值来知道你是否需要清理另一个 FragmentManager
。我将以您的代码为例:
@Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
if(isLastFragmentSupportType && lastFragmentShowed)
{//As your last fragment was a support type you need to clear your supportFragmentManager
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment,TAG1)
.commit();
lastFragmentTag = TAG1;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
break;
}
//And so on with the others
您需要检查您要使用的片段类型(支持与否),并检查这些变量以查看最后一个片段是否属于不同类型。如果是这种情况,请将另一个 fragmentmanager 清理到 "clear" 屏幕,这样它们就不会重叠。
还可以使用 TAGS 来识别和检索您当前的片段,这样您的代码就不需要 Fragment
变量。
最后使用 onSavedInstanceState
以保留这些值以备不时之需。
希望对您有所帮助:)
这个答案的灵感来自于 zozelfelfo 的答案。
使用这两种方法替换片段而不是getFragmentManager.beginTransaction.replace...
private void replaceFragment(Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && isLastFragmentSupportType) {
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
}
private void replaceFragment(android.support.v4.app.Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && !isLastFragmentSupportType) {
Fragment fr = getFragmentManager().findFragmentByTag(lastFragmentTag);
getFragmentManager().beginTransaction().remove(fr).commit();
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = true;
}
我正在使用 BottomNavigationView
作为选项卡栏并将片段切换为选项卡。除一个片段外,所有片段均为 Support Fragments
(最后一个片段为 PreferenceFragment
)。我使用 "hide-add-show" 而不是 "remove-replace"。因此,可以保留其他选项卡中片段的状态。
要切换的原函数:
private Fragment lastFragment = null;
private void switchFragment(Fragment fragment) {
if (lastFragment != fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (null != lastFragment) {
transaction.hide(lastFragment);
}
lastFragment = fragment;
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
}
我既不使用标记也不使用布尔值,只是想保留对最后一个片段对象的引用。因此,切换时,只需使用任何片段的实例调用 switchFragment()
:
private Object lastFragment = null;
private void switchFragment(Object fragment) {
if (lastFragment != fragment) {
if (null != lastFragment) {
if (lastFragment instanceof android.support.v4.app.Fragment) {
hideFragment((android.support.v4.app.Fragment) lastFragment);
} else if (lastFragment instanceof android.app.Fragment) {
hideFragment((android.app.Fragment) lastFragment);
}
}
lastFragment = fragment;
if (fragment instanceof android.support.v4.app.Fragment) {
showFragment((android.support.v4.app.Fragment) fragment);
} else if (fragment instanceof android.app.Fragment) {
showFragment((android.app.Fragment) fragment);
}
}
}
因此,此函数仍然执行相同的操作,但通过检查目标 class 在 Support Fragment
和 Native Fragment
之间切换。辅助函数:
// Support Version:
private void hideFragment(android.support.v4.app.Fragment fragment) {
getSupportFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.support.v4.app.Fragment fragment) {
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
// Native Version:
private void hideFragment(android.app.Fragment fragment) {
getFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.app.Fragment fragment) {
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
为了避免混淆,我删除了 import
,因此 classes 需要全名。
我的 activity:
里有这样的东西@Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 2: {
SwipeRefreshListFragment swipeFragment = new Fragment_List_Of_Assessments();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, swipeFragment)
.commit();
break;
}
case 3: {
fragment = new Fragment_Report();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 4: {
fragment = new Fragment_Settings();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
default:
break;
}
}
The program automatically loads case1, but when case2 is selected, getSupportFragmentManager loads the Fragment on top of case1.我想同时使用 supportFragmentManager 和 FragmentManager 有一些问题。他们似乎有自己的堆栈。问题是我不能只使用其中一个,因为 SwipeToRefresh Android 示例使用需要支持的 ListView。v4.Fragment 需要旧的 FragmentManager。那么如何将两个 FragmentManagers 集成在一起呢?
我在使用 PreferenceFragment(支持库版本不支持)时完成了类似的事情。为了实现这一点,我在 Activity 中保留了一对布尔值(isLastFragmentSupportType
和 lastFragmentShowed
)以及一个字符串(lastFragmentTag
)。
一开始你的 Activity 会让它们都为 false。当你添加一个新的 Fragment 时,你使用这两个布尔值来知道你是否需要清理另一个 FragmentManager
。我将以您的代码为例:
@Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
if(isLastFragmentSupportType && lastFragmentShowed)
{//As your last fragment was a support type you need to clear your supportFragmentManager
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment,TAG1)
.commit();
lastFragmentTag = TAG1;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
break;
}
//And so on with the others
您需要检查您要使用的片段类型(支持与否),并检查这些变量以查看最后一个片段是否属于不同类型。如果是这种情况,请将另一个 fragmentmanager 清理到 "clear" 屏幕,这样它们就不会重叠。
还可以使用 TAGS 来识别和检索您当前的片段,这样您的代码就不需要 Fragment
变量。
最后使用 onSavedInstanceState
以保留这些值以备不时之需。
希望对您有所帮助:)
这个答案的灵感来自于 zozelfelfo 的答案。
使用这两种方法替换片段而不是getFragmentManager.beginTransaction.replace...
private void replaceFragment(Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && isLastFragmentSupportType) {
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
}
private void replaceFragment(android.support.v4.app.Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && !isLastFragmentSupportType) {
Fragment fr = getFragmentManager().findFragmentByTag(lastFragmentTag);
getFragmentManager().beginTransaction().remove(fr).commit();
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = true;
}
我正在使用 BottomNavigationView
作为选项卡栏并将片段切换为选项卡。除一个片段外,所有片段均为 Support Fragments
(最后一个片段为 PreferenceFragment
)。我使用 "hide-add-show" 而不是 "remove-replace"。因此,可以保留其他选项卡中片段的状态。
要切换的原函数:
private Fragment lastFragment = null;
private void switchFragment(Fragment fragment) {
if (lastFragment != fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (null != lastFragment) {
transaction.hide(lastFragment);
}
lastFragment = fragment;
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
}
我既不使用标记也不使用布尔值,只是想保留对最后一个片段对象的引用。因此,切换时,只需使用任何片段的实例调用 switchFragment()
:
private Object lastFragment = null;
private void switchFragment(Object fragment) {
if (lastFragment != fragment) {
if (null != lastFragment) {
if (lastFragment instanceof android.support.v4.app.Fragment) {
hideFragment((android.support.v4.app.Fragment) lastFragment);
} else if (lastFragment instanceof android.app.Fragment) {
hideFragment((android.app.Fragment) lastFragment);
}
}
lastFragment = fragment;
if (fragment instanceof android.support.v4.app.Fragment) {
showFragment((android.support.v4.app.Fragment) fragment);
} else if (fragment instanceof android.app.Fragment) {
showFragment((android.app.Fragment) fragment);
}
}
}
因此,此函数仍然执行相同的操作,但通过检查目标 class 在 Support Fragment
和 Native Fragment
之间切换。辅助函数:
// Support Version:
private void hideFragment(android.support.v4.app.Fragment fragment) {
getSupportFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.support.v4.app.Fragment fragment) {
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
// Native Version:
private void hideFragment(android.app.Fragment fragment) {
getFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.app.Fragment fragment) {
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
为了避免混淆,我删除了 import
,因此 classes 需要全名。