在活动之间保留片段信息

时间:2014-05-28 12:11:32

标签: android android-fragments android-actionbaractivity

我有我的主要活动actionbaractivity你可以在屏幕上浏览一些碎片,在每个片段上你有imageViewListView,你可以点击任何项目,图像会改变。同样在菜单选项中,您有一个按钮,您可以在其中更改为几乎完全相同的活动:actiobbaractivity两个也可以将此按钮更改为活动一个 我能做的是在滑动碎片时保留图像,但不能通过改变活动来保持碎片的状态。

例如 我正处于片段3的活动中,图像为“某物”。我点击按钮更改为活动二,我在这里做事情然后,我点击按钮更改为活动一,我想看到我的片段3与图像:“东西”而不是默认片段1和默认图片

我为每个活动使用ActionBarActivity,FragmentStatePagerAdapter和Fragment

感谢您的帮助

1 个答案:

答案 0 :(得分:0)

根据活动和片段生命周期(http://developer.android.com/reference/android/app/Activity.html#ActivityLifecyclehttp://developer.android.com/guide/components/fragments.html#Lifecycle),在活动/片段更改之间保持状态的最可靠方法是使用默认API来保存和恢复状态:

当活动/片段被解除时(由于屏幕旋转等配置更改或者因为用户请求转到另一个活动/片段),您可以将其状态保存在Bundle对象中。在创建时,您可以恢复其保存状态,从而重新创建与用户离开的实例完全相同的新实例 - 因此用户感觉没有任何更改。这不依赖于您正在使用的活动/片段的特定子类。

我已经实现了你想要的东西:在我的例子中,一个片段包含一个带按钮的菜单,每个按钮会引导用户到另一个包含带有“后退”按钮的子菜单的片段。因此,如果用户从菜单进入子菜单1,然后回到菜单,然后回到子菜单2,然后回到菜单,最后再回到子菜单1,我希望子菜单1看起来就像用户第一次离开它一样

为此,我创建了:

1)interface通过我的活动定义我的子菜单类型implemented,以便他们可以在我的子菜单之间进行更改

2)主通用class,我的所有子菜单extend都有一个Bundle对象来存储他们的状态

3)在我的活动中,我有一个Bundle数组,能够存储每个子菜单的一个实例(因为我只对恢复最后一个状态感兴趣,所以我不需要多个)

界面(第1项):

    public interface SubmenusManager {
      public static enum Submenus {
        ROOTMENU, 
        SUBMENU1,
        SUBMENU2;

        private static final int size = Submenus.values().length;
        public static int size() {
          return size;
        }
        public static int getId(Submenus test) {
          switch(test) {
            case SUBMENU1: 
              return 1;

            case SUBMENU2: 
              return 2;

            case ROOTMENU: 
            default:    
              return 0;
          }
        }
      }

      public void cloneCurrentSubmenuState(Parcelable toOverwrite);
      public Bundle getLastStoredSubmenuState(Submenus submenu);
      public void setCurrentSubmenuTo(Submenus submenu);
    }

通用类(第2项):

    public class MenuFragment extends Fragment {
      private Bundle menuData = new Bundle();
      public static String RESTORE_MAIN_OBJECT = "restore_main";

      public Bundle getMenuData() {
        return menuData;
      }
      public Bundle cloneMenuData() {
        return new Bundle(menuData);
      }

      public void setMenuData(Bundle menuData) {
        this.menuData = menuData;
      }
    }

其中一项活动(第3项):

    public class ExampleAct extends FragmentActivity implements SubmenusManager {
      /**
      * instance variables
      */
      private MenuFragment mMenu; 
      private Bundle [] menuData; //  the Array of Bundles!
      private static final String CONTAINER = "parcelable_container";

      private static final String SUBMENU = "saved_submenu";
      private Submenus curSubmenu = Submenus.ROOTMENU; // the default state is the ROOTMENU
      private boolean restoreLastSavedState = false;

      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) { // first time creating this activity
          menuData = new Bundle[Submenus.size()];
        } else { // this activity has a saved state from before
          // restore all the data from all the submenus
          menuData = (Bundle[]) savedInstanceState.getParcelableArray(CONTAINER);
          // restore the info about which is the current active submenu
          curSubmenu = (Submenus) savedInstanceState.getSerializable(SUBMENU);
        }

        buildMenuFragment(true);

        //(...) stuff
      }

      private void buildMenuFragment(boolean restoreState) {
        // (re)builds fragment inside menu. 
        // restoreState flags whether activity should look for
        // saved state data and restore it
        restoreLastSavedState = restoreState;
        switch(curSubmenu) { 
          // Eclipse warns you about which are the constants in your enum
          case ROOTMENU:
            mMenu = new FragmentRootMenu();
            break;
          case SUBMENU1:
            mMenu = new FragmentSubmenu1();
            break;
          case SUBMENU2:
            mMenu = new FragmentSubmenu2();
            break;
        }

        getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.menu_frame, mMenu)
        .commit();
      }

      @Override
      public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putSerializable(SUBMENU, curSubmenu);
        cloneCurrentSubmenuState(mMenu.getMenuData().
          getParcelable(MenuFragment.RESTORE_MAIN_OBJECT));
        outState.putParcelableArray(CONTAINER, menuData);

        // (...) stuff
      }

      @Override
      public void cloneCurrentSubmenuState(Parcelable toOverwrite) {
        if (menuData == null) menuData = new Bundle[Submenus.size()];

        if (toOverwrite != null) 
          mMenu.getMenuData().putParcelable(MenuFragment.RESTORE_MAIN_OBJECT, toOverwrite);

          menuData[Submenus.getId(curSubmenu)] = mMenu.cloneMenuData();
      }

      @Override
      public Bundle getLastStoredSubmenuState(Submenus forThisSubmenu) {
        return
          (menuData == null || !restoreLastSavedState) ? new Bundle() : menuData[Submenus.getId(forThisSubmenu)];
      }

      @Override
      public void setCurrentSubmenuTo(Submenus toThisSubmenu) {
        if (mMenu != null) {
          cloneCurrentSubmenuState(mMenu.getMenuData().
            getParcelable(MenuFragment.RESTORE_MAIN_OBJECT));
        }
        curSubmenu = toThisSubmenu;
        buildMenuFragment(true);
      }

其中一个子菜单(第2项的扩展名):

    public class FragmentSubmenu1 extends MenuFragment {
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_submenu1, null);
      }

      @Override
      public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        init();
      }

      public void init() {
        // (...) stuff

        MyParcelableObject tmp = null; // MyParcelableObject is a class 
                                       // that implements Parcelable and stores 
                                       // relevant info to rebuild this menu 
                                       // from a saved state
        SubmenusManager m = (SubmenusManager) getActivity(); // remember activity implements SubmenusManager
        Bundle bnd = m.getLastStoredSubmenuState(SubmenusManager.Submenus.SUBMENU1);
        if (bnd != null) tmp = bnd.getParcelable(MenuFragment.RESTORE_MAIN_OBJECT);
        if (tmp == null) {
          tmp = new MyParcelableObject();
          tmp.buildFromScratch(); // initializes with default data
        }

        // back button
        Button backToMainMenu = (Button) getView().findViewById(R.id.submenu1_back);
        backToMainMenu.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View v) {
            ((SubmenusManager) getActivity()).
              setCurrentSubmenuTo(SubmenusManager.Submenus.ROOTMENU);
          }
        });

        // (...) stuff
      }
    }

Root菜单(第2项的扩展名):

    public class FragmentRootMenu extends MenuFragment {
      View myView;

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        myView = inflater.inflate(R.layout.fragment_rootmenu, null);
        return myView;
      }

      @Override
      public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        init();
      }

      public void init() {
        Button btnSubmenu1 = (Button) myView.findViewById(R.id.btn_call_submenu1);

        btnSubmenu1.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View v) {
            ((SubmenusManager) getActivity()).
              setCurrentSubmenuTo(SubmenusManager.Submenus.SUBMENU1);
          }
        });

        Button btnSubmenu2 = (Button) myView.findViewById(R.id.btn_call_submenu2);

        btnSubmenu2.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View v) {
            ((SubmenusManager) getActivity()).
              setCurrentSubmenuTo(SubmenusManager.Submenus.SUBMENU2);
          }
        });
      }
    }

为了在活动之间工作,您需要做的就是将存储所有片段的最后状态(在我的情况下,将是Bundle [] menuData)的对象传递给通过其调用的活动Intent;你可以像ExampleAct onCreate()中那样恢复它。你也可以将Bundle []包装在一个自定义的Parcelable对象中(非常类似于我的示例MyParcelableObject;如果使用数组是一个问题,那么我会在HashMap之内)。

这里是如何在活动之间传递Parcelable: How to send an object from one Android Activity to another using Intents?