我正在使用HashMap
片段的后台堆栈。要保存backstack和当前片段,我使用下面的代码:
public class MainActivity extends AppCompatActivity {
private HashMap<String, Stack<Fragment>> mStacks;
public static final String TAB_PROFILE = "tab_profile";
public static final String TAB_DASHBOARD = "tab_dashboard";
public static final String TAB_CHATS = "tab_chats";
public static final String TAB_SETTINGS = "tab_settings";
private String mCurrentTab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViews();
if (savedInstanceState != null) {
mCurrentTab = savedInstanceState.getString("currentTab");
mStacks = (HashMap<String, Stack<Fragment>>) savedInstanceState.getSerializable("stacks");
} else
selectedTab(TAB_DASHBOARD);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("stacks", mStacks);
outState.putString("currentTab", mCurrentTab);
}
private void setupViews() {
mStacks = new HashMap<>();
mStacks.put(TAB_PROFILE, new Stack<>());
mStacks.put(TAB_DASHBOARD, new Stack<>());
mStacks.put(TAB_CHATS, new Stack<>());
mStacks.put(TAB_SETTINGS, new Stack<>());
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setSelectedItemId(R.id.action_dashboard);
BottomNavigationViewHelper.removeShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.action_profile:
selectedTab(TAB_PROFILE);
return true;
case R.id.action_dashboard:
selectedTab(TAB_DASHBOARD);
return true;
case R.id.action_chats:
selectedTab(TAB_CHATS);
return true;
case R.id.action_settings:
selectedTab(TAB_SETTINGS);
return true;
}
return true;
});
bottomNavigationView.setOnNavigationItemReselectedListener(item -> {
if (mStacks.get(mCurrentTab).size() != 1) {
mStacks.get(mCurrentTab).clear();
switch (item.getItemId()) {
case R.id.action_profile:
selectedTab(TAB_PROFILE);
break;
case R.id.action_dashboard:
selectedTab(TAB_DASHBOARD);
break;
case R.id.action_chats:
selectedTab(TAB_CHATS);
break;
case R.id.action_settings:
selectedTab(TAB_SETTINGS);
break;
}
}
});
}
private void selectedTab(String tabId) {
mCurrentTab = tabId;
if(mStacks.get(tabId).size() == 0){
if(tabId.equals(TAB_PROFILE)){
Fragment fragment = new ProfileFragment();
Bundle args = new Bundle();
args.putSerializable("user", Globals.getCurrentUser());
fragment.setArguments(args);
pushFragments(tabId, fragment,true);
} else if(tabId.equals(TAB_DASHBOARD)){
pushFragments(tabId, new DashboardFragment(),true);
}else if(tabId.equals(TAB_CHATS)){
pushFragments(tabId, new GroupsFragment(),true);
}else if(tabId.equals(TAB_SETTINGS)){
pushFragments(tabId, new SettingsFragment(),true);
}
}else {
pushFragments(tabId, mStacks.get(tabId).lastElement(),false);
}
}
public void pushFragments(String tag, Fragment fragment, boolean shouldAdd){
if(shouldAdd)
mStacks.get(tag).push(fragment);
FragmentManager manager = getFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, fragment);
ft.commit();
}
public void popFragments(){
Fragment fragment = mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2);
mStacks.get(mCurrentTab).pop();
FragmentManager manager = getFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, fragment);
ft.commit();
}
@Override
public void onBackPressed() {
if(mStacks.get(mCurrentTab).size() == 1){
finish();
return;
}
popFragments();
}
}
使用
设置新片段((MainActivity)context).pushFragments(MainActivity.TAB_CHATS, fragment,true);
布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="@color/background_material_light"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/bottom_navigation"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="@color/waPrimary"
app:itemIconTint="@color/white"
app:itemTextColor="@color/white"
app:menu="@menu/menu_bottom_navigation" />
屏幕旋转时一切正常,但应用程序在应用程序隐藏时崩溃。
java.lang.RuntimeException:Parcel:无法编组值%FragmentName%{c985244#2 id = 0x7f090051}
正如我所读到的那样,当我试图通过的其中一个对象不是Parceable
时,却会发生这种情况,但不知道如何解决这个问题。有什么想法吗?
UPD
在我制作了所有片段Serializable
后,新的异常抛出
java.lang.RuntimeException:Parcelable遇到IOException编写可序列化对象(name =%FragmentName%)
...
引起:java.io.NotSerializableException:android.support.v7.widget.RecyclerView
UPD2
似乎找到了一个解决方案 - transient
属性。现在我试图让所有不可序列化的对象成为瞬态。
UPD3
它有所帮助,但我不知道它是否足够有效。
答案 0 :(得分:2)
这是我的建议:
这样,每个片段自动维护自己的后台堆栈,您不必保存任何状态,而且它都是Just Works™。
一些可能有帮助的示例代码。
public class MainActivity extends AppCompatActivity {
private Fragment mProfileFragment;
private Fragment mDashboardFragment;
private Fragment mChatsFragment;
private Fragment mSettingsFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
// Init fragments
}
else {
// Find last active fragments in fragment manager
}
setupViews();
}
private void setupViews() {
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setSelectedItemId(R.id.action_dashboard);
BottomNavigationViewHelper.removeShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
Fragment fragment;
switch (item.getItemId()) {
case R.id.action_profile:
fragment = mProfileFragment;
break;
case R.id.action_dashboard:
fragment = mDashboardFragment;
break;
case R.id.action_chats:
fragment = mChatsFragment;
break;
case R.id.action_settings:
fragment = mSettingsFragment;
break;
}
// Replace the currently active fragment which will be
// managing its own backstack
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frament_container, fragment)
.commit();
});
}
}
你的一个片段会把东西推到自己的堆栈上:
public class ProfileFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.id.fragment_layout, container, false);
Button button = view.findViewById(R.id.some_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Fragment someFragmentToPush = new SomeFragmentToPush();
// Use the child fragment manager to keep UI
// local to this fragment instance, adding to backstack
// for automatic popping on pressing back
getChildFragmentManager().beginTransaction()
.add(R.id.fragment_layout, someFragmentToPush)
.addToBackStack(null)
.commit();
}
});
return view;
}
}
希望有所帮助!