将片段的HashMap传递给bundle

时间:2017-11-12 15:18:04

标签: android android-fragments

我正在使用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

它有所帮助,但我不知道它是否足够有效。

1 个答案:

答案 0 :(得分:2)

这是我的建议:

  1. 您的活动会保留对底部导航切换所需的四个片段的引用。
  2. 在切换底部导航时,您替换 活动片段管理器中的当前片段。
  3. 在给定片段上,当您与用户界面进行互动时,内容推送到片段子片段管理器。
  4. 这样,每个片段自动维护自己的后台堆栈,您不必保存任何状态,而且它都是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;
        }
    }
    

    希望有所帮助!