如何在选项卡中没有后台堆栈的情况下维护片段状态?
How to maintain fragment state without backstack in tab?
我试图在 onSaveInstanceState
中保存片段状态,但是当我返回片段时,它总是重新加载而不是从上一个状态开始。
我查看了 onCreateView
和 onActivityCreated
,它始终将 onSaveInstanceState
设为空。
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAdd)
mStacks.get(tag).push(fragment); // push fragment on stack
ft.replace(android.R.id.tabcontent, fragment);
if (shouldAdd)
ft.addToBackStack(tag);
ft.commit();
}
因为我无法使用 backstack
因为在选项卡中返回堆栈没有用。任何帮助将不胜感激。
我认为你应该使用 Shared Preferences 的想法,这比使用本地文件或数据库更快,而且绝对更容易编码。一个很好的 Android 网页 @ Storage Options。我将从网页中获取一些示例代码,并根据您的需要进行一些更改。
首先,在 onCreate() 覆盖方法中获取从首选项中保存的数据:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean("silentMode", false);
...
}
接下来,由于各种原因,让我们在片段停止或退出之前保存数据。通过覆盖 onDetach
方法实现此目的,网页覆盖 onStop()
代替。
@Override
public void onDetach() {
super.onDetach();
...
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("silentMode", mSilentMode);
// Commit the edits!
editor.commit();
}
祝你好运,玩得开心!
在这种情况下,您必须自己管理片段的状态。我不知道你的代码是如何工作的,所以我唯一能做的就是给你一些提示。
您需要执行的第一件事是保存片段的状态。假设所有片段都有唯一的 ID。在这种情况下,您需要创建一个将保留所有州的地图:
private final Map<String, Fragment.SavedState> mFragmentStates = new HashMap<>();
private void saveFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState =
getSupportFragmentManager().saveFragmentInstanceState(fragment);
mFragmentStates.put(id, fragmentState);
}
您需要为要删除的片段调用此方法。然后我们需要恢复片段的状态,这就是我们可以做到的:
private void restoreFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState = mFragmentStates.remove(id);
if (fragmentState != null) {
fragment.setInitialSavedState(savedState);
}
}
您需要在将片段添加到事务之前调用此方法。
提供的代码应该可以正常工作,但要使其在 activity 游戏中正常工作,我们需要正确保存和恢复 mFragmentStates
:
private static final String KEY_FRAGMENT_STATES = "fragment_states";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Your code ... */
if (savedInstanceState != null) {
Bundle fragmentStates =
savedInstanceState.getParcelable(KEY_FRAGMENT_STATES);
if (fragmentStates != null) {
for (String id : fragmentStates.keySet()) {
Fragment.SavedState fragmentState =
fragmentStates.getParcelable(id);
mFragmentStates.put(id, fragmentState);
}
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/* Your code ... */
Bundle fragmentStates = new Bundle(mFragmentStates.size());
for (Map.Entry<String, Fragment.SavedState> entry : mFragmentStates.entrySet()) {
fragmentStates.put(entry.getKey(), entry.getValue());
}
outState.putParcelable(KEY_FRAGMENT_STATES, fragmentStates);
}
也可以看看FragmentStatePagerAdapterclass。它使用相同的方法来管理 ViewPager
片段的状态。
更新:所以你的代码应该看起来像这样:
private Fragment mCurrentFragment;
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (shouldAdd) {
mStacks.get(tag).push(fragment); // push fragment on stack
}
if (mCurrentFragment != null) {
saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
}
mCurrentFragment = fragment;
restoreFragmentState(fragment.getClass().getName(), fragment);
transaction.replace(android.R.id.tabcontent, fragment);
if (shouldAdd) {
// You shouldn't use back-stack when managing fragment states by yourself.
transaction.addToBackStack(tag);
}
transaction.commit();
}
在此示例中,我使用片段的 class 名称作为 ID,因此所有片段必须具有不同的 classes。但是您可以使用任何其他唯一值作为 id。我必须提到的另一件重要的事情是,当你自己管理片段状态时,你不应该使用 back-stack。 Back-stack 执行类似的状态管理,您可能会发生冲突。
您正在执行 替换 片段,这就是片段被销毁的原因。您可以在下面尝试。在这里,我在单个 FragmentTransaction 中做了两件事,我正在 添加 一个新片段和 隐藏 现有片段片段.
假设我们在片段 A
之上添加片段 B
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(android.R.id.tabcontent, fragmentB, tagFragmentB)
.hide(fragmentManager.findFragmentByTag(tagFragmentA))
.addToBackStack(tag)
.commit();
一旦你按回键,它将删除片段B & 显示具有相同状态的片段 A(在添加片段 B 之前)
请注意这里 tagFragmentA & tagFragmentB 是片段 A & B分别加
我不清楚您用于实现选项卡的方式。
我猜从,
ft.replace(android.R.id.tabcontent, fragment);
您可能已经实施了 FragmentTabHost。
写一个 customFragmentTabhost 并覆盖
@Override
public void onTabChanged(String tabId) {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
if (tabId.equals(“Tab1”)) {
TabFragment1 fragment1 = null;
if (getSupportFragmentManager().findFragmentByTag(“Tab1”) == null) {
fragment1 = new TabFragment1();
} else {
fragment1 = (TabFragment1) getSupportFragmentManager().findFragmentByTag("Tab1");
}
t.replace(R.id.realContent, fragment1, "Tab1").addToBackStack(null).commit();
}
}
更新:
确保Activity不在方向上重新创建,如果是这样setRetainInstance(true),这样即使activity在方向改变时重新创建,碎片也会被保留。
请为片段中的任何视图提供 ID。 Android 系统保持状态很重要。
clearBackStackEntry();
rl.setVisibility(View.GONE);
getSupportFragmentManager().beginTransaction()
.replace(FRAGMENT_CONTAINER, new HomeScreen())
.addToBackStack(null).commit();
private void clearBackStackEntry() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count > 0) {
getSupportFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
TRY THIS AND One more for fragment also try this: but use support.v4.app.Fragment, May be it will help you
Fragment fr = new main();
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
// getActivity().finish();
声明
setRetainInstance(true)
在您的片段 onCreate() 中。重新创建以前的状态
link 将有助于理解 setRetainInstance 的工作原理。
Understanding Fragment's setRetainInstance(boolean)
Why use Fragment#setRetainInstance(boolean)?
谢谢:)
处理这些事情很简单。我可以给你示例来处理我们添加的 Fr 代理的背压。
我已经声明了一个片段堆栈并将所有片段压入其中;
public static Stack<Fragment> fragmentStack;
制作这样的方法:
public static void replaceFragementsClick(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
}
DashBoardActivity.fragmentStack.push(fragementObj);
} catch (Exception e) {
e.printStackTrace();
}
}
也试试这个:
public static void replaceFragementsClickBack(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
DashBoardActivity.fragmentStack.pop();
}
} catch (Exception e) {
e.printStackTrace();
}
}
在您添加的基础 activity 中,覆盖像这样的反压:
@Override
public void onBackPressed() {
/**
* Do Current Fragment Pop
* */
fragmentStack.pop();
if(fragmentStack.size() >0){
Bundle bunldeObj = new Bundle();
//******Exit from Current Fragment
Fragment fragment = fragmentStack.pop();
// fragmentStack.push(fragment);
if(fragment instanceof PhotosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoDetatilFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoFullViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof HomeFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Home");
}else if(fragment instanceof VideosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof MusicFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof MusicListFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof InstallAppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else if(fragment instanceof MessageFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof MessageDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof LocateDeviceFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Locate Device");
}else if(fragment instanceof FilesFragmentBottomBar){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Files");
}else if(fragment instanceof AppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else {
super.onBackPressed();
Intent intent = new Intent(DashBoardActivity.this,ConnectDeviceActivity.class);
startActivity(intent);
finish();
}
}
我试图在 onSaveInstanceState
中保存片段状态,但是当我返回片段时,它总是重新加载而不是从上一个状态开始。
我查看了 onCreateView
和 onActivityCreated
,它始终将 onSaveInstanceState
设为空。
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAdd)
mStacks.get(tag).push(fragment); // push fragment on stack
ft.replace(android.R.id.tabcontent, fragment);
if (shouldAdd)
ft.addToBackStack(tag);
ft.commit();
}
因为我无法使用 backstack
因为在选项卡中返回堆栈没有用。任何帮助将不胜感激。
我认为你应该使用 Shared Preferences 的想法,这比使用本地文件或数据库更快,而且绝对更容易编码。一个很好的 Android 网页 @ Storage Options。我将从网页中获取一些示例代码,并根据您的需要进行一些更改。
首先,在 onCreate() 覆盖方法中获取从首选项中保存的数据:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean("silentMode", false);
...
}
接下来,由于各种原因,让我们在片段停止或退出之前保存数据。通过覆盖 onDetach
方法实现此目的,网页覆盖 onStop()
代替。
@Override
public void onDetach() {
super.onDetach();
...
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("silentMode", mSilentMode);
// Commit the edits!
editor.commit();
}
祝你好运,玩得开心!
在这种情况下,您必须自己管理片段的状态。我不知道你的代码是如何工作的,所以我唯一能做的就是给你一些提示。
您需要执行的第一件事是保存片段的状态。假设所有片段都有唯一的 ID。在这种情况下,您需要创建一个将保留所有州的地图:
private final Map<String, Fragment.SavedState> mFragmentStates = new HashMap<>();
private void saveFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState =
getSupportFragmentManager().saveFragmentInstanceState(fragment);
mFragmentStates.put(id, fragmentState);
}
您需要为要删除的片段调用此方法。然后我们需要恢复片段的状态,这就是我们可以做到的:
private void restoreFragmentState(String id, Fragment fragment) {
Fragment.SavedState fragmentState = mFragmentStates.remove(id);
if (fragmentState != null) {
fragment.setInitialSavedState(savedState);
}
}
您需要在将片段添加到事务之前调用此方法。
提供的代码应该可以正常工作,但要使其在 activity 游戏中正常工作,我们需要正确保存和恢复 mFragmentStates
:
private static final String KEY_FRAGMENT_STATES = "fragment_states";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Your code ... */
if (savedInstanceState != null) {
Bundle fragmentStates =
savedInstanceState.getParcelable(KEY_FRAGMENT_STATES);
if (fragmentStates != null) {
for (String id : fragmentStates.keySet()) {
Fragment.SavedState fragmentState =
fragmentStates.getParcelable(id);
mFragmentStates.put(id, fragmentState);
}
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/* Your code ... */
Bundle fragmentStates = new Bundle(mFragmentStates.size());
for (Map.Entry<String, Fragment.SavedState> entry : mFragmentStates.entrySet()) {
fragmentStates.put(entry.getKey(), entry.getValue());
}
outState.putParcelable(KEY_FRAGMENT_STATES, fragmentStates);
}
也可以看看FragmentStatePagerAdapterclass。它使用相同的方法来管理 ViewPager
片段的状态。
更新:所以你的代码应该看起来像这样:
private Fragment mCurrentFragment;
public void navigateFragment(String tag, Fragment fragment,
boolean shouldAdd) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (shouldAdd) {
mStacks.get(tag).push(fragment); // push fragment on stack
}
if (mCurrentFragment != null) {
saveFragmentState(mCurrentFragment.getClass().getName(), mCurrentFragment);
}
mCurrentFragment = fragment;
restoreFragmentState(fragment.getClass().getName(), fragment);
transaction.replace(android.R.id.tabcontent, fragment);
if (shouldAdd) {
// You shouldn't use back-stack when managing fragment states by yourself.
transaction.addToBackStack(tag);
}
transaction.commit();
}
在此示例中,我使用片段的 class 名称作为 ID,因此所有片段必须具有不同的 classes。但是您可以使用任何其他唯一值作为 id。我必须提到的另一件重要的事情是,当你自己管理片段状态时,你不应该使用 back-stack。 Back-stack 执行类似的状态管理,您可能会发生冲突。
您正在执行 替换 片段,这就是片段被销毁的原因。您可以在下面尝试。在这里,我在单个 FragmentTransaction 中做了两件事,我正在 添加 一个新片段和 隐藏 现有片段片段.
假设我们在片段 A
之上添加片段 B FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(android.R.id.tabcontent, fragmentB, tagFragmentB)
.hide(fragmentManager.findFragmentByTag(tagFragmentA))
.addToBackStack(tag)
.commit();
一旦你按回键,它将删除片段B & 显示具有相同状态的片段 A(在添加片段 B 之前)
请注意这里 tagFragmentA & tagFragmentB 是片段 A & B分别加
我不清楚您用于实现选项卡的方式。 我猜从,
ft.replace(android.R.id.tabcontent, fragment);
您可能已经实施了 FragmentTabHost。
写一个 customFragmentTabhost 并覆盖
@Override
public void onTabChanged(String tabId) {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
if (tabId.equals(“Tab1”)) {
TabFragment1 fragment1 = null;
if (getSupportFragmentManager().findFragmentByTag(“Tab1”) == null) {
fragment1 = new TabFragment1();
} else {
fragment1 = (TabFragment1) getSupportFragmentManager().findFragmentByTag("Tab1");
}
t.replace(R.id.realContent, fragment1, "Tab1").addToBackStack(null).commit();
}
}
更新:
确保Activity不在方向上重新创建,如果是这样setRetainInstance(true),这样即使activity在方向改变时重新创建,碎片也会被保留。
请为片段中的任何视图提供 ID。 Android 系统保持状态很重要。
clearBackStackEntry();
rl.setVisibility(View.GONE);
getSupportFragmentManager().beginTransaction()
.replace(FRAGMENT_CONTAINER, new HomeScreen())
.addToBackStack(null).commit();
private void clearBackStackEntry() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count > 0) {
getSupportFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
TRY THIS AND One more for fragment also try this: but use support.v4.app.Fragment, May be it will help you
Fragment fr = new main();
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
// getActivity().finish();
声明
setRetainInstance(true)
在您的片段 onCreate() 中。重新创建以前的状态
link 将有助于理解 setRetainInstance 的工作原理。
Understanding Fragment's setRetainInstance(boolean)
Why use Fragment#setRetainInstance(boolean)?
谢谢:)
处理这些事情很简单。我可以给你示例来处理我们添加的 Fr 代理的背压。
我已经声明了一个片段堆栈并将所有片段压入其中;
public static Stack<Fragment> fragmentStack;
制作这样的方法:
public static void replaceFragementsClick(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
}
DashBoardActivity.fragmentStack.push(fragementObj);
} catch (Exception e) {
e.printStackTrace();
}
}
也试试这个:
public static void replaceFragementsClickBack(Fragment fragementObj, Bundle bundleObj, String title){
try {
FragmentManager fragmentManager = ((FragmentActivity) mContext).getSupportFragmentManager();
if (fragementObj != null) {
fragementObj.setArguments(bundleObj);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragementObj).commit();
DashBoardActivity.fragmentStack.pop();
}
} catch (Exception e) {
e.printStackTrace();
}
}
在您添加的基础 activity 中,覆盖像这样的反压:
@Override
public void onBackPressed() {
/**
* Do Current Fragment Pop
* */
fragmentStack.pop();
if(fragmentStack.size() >0){
Bundle bunldeObj = new Bundle();
//******Exit from Current Fragment
Fragment fragment = fragmentStack.pop();
// fragmentStack.push(fragment);
if(fragment instanceof PhotosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoDetatilFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof PhotoFullViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Photos");
}else if(fragment instanceof HomeFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Home");
}else if(fragment instanceof VideosFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof VideoViewFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Videos");
}else if(fragment instanceof MusicFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof MusicListFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Music");
}else if(fragment instanceof InstallAppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else if(fragment instanceof MessageFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof MessageDetailFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Messages");
}else if(fragment instanceof LocateDeviceFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Locate Device");
}else if(fragment instanceof FilesFragmentBottomBar){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Files");
}else if(fragment instanceof AppsFragment){
bunldeObj.putString("position", "4");
replaceFragementsClick(fragment,bunldeObj,"Apps");
}else {
super.onBackPressed();
Intent intent = new Intent(DashBoardActivity.this,ConnectDeviceActivity.class);
startActivity(intent);
finish();
}
}