简体   繁体   中英

Orientation Change Causes Series of Fragments in Activity Disappear and Do Not Apply Save Instance State

So I hit another roadblock in my development project.

This time it involves fragments with regard to changing orientation and persisting their saved instance states. Please pardon me if it involves two questions but they involve the same problem catalyst which is the orientation change. I will try to be as detailed as possible so please bear with me.

I have a bunch of fragments using a single activity as host. In my mind, my fragments are grouped by sections although they are still modular/reusable by code.

So I have 3 fragments that are hosted inside a single fragment that implements a navigation drawer. The logical flow goes like this:

Frag1 -> (Press Next) -> Frag2 -> (Press Next) -> Frag3

The creation of Frag2 and Frag3 calls addToBackStack() in committing the transaction in FragmentManager. The problem is when I am in Frag2 or Frag3 and then change the device orientation, the fragments disappear and then show Frag1.

The other problem is than when I am in Frag1, then type some text in the EditText, and then change the orientation, the text disappears despite implementing onSaveInstanceState(Bundle bundle).

Here are my relevant code snippets:

Code snippet for creating Frag1 in Activity.java

@Override
public void onNavigationDrawerItemSelected(int position) {
    // init the fragment (with a default fragment, not null)
    rootFragment = PlaceholderFragment.newInstance(position + 1);
    // Position number from navigation sidebar starts from 0.
    // Since position starts from 0, add 1 to match section number
    // as implemented in {@link #onSectionAttached()}
    switch (position) {
        case 0: // Other section
            rootFragment = PlaceholderFragment.newInstance(position + 1);
            break;
        case 1: // Frag1
            rootFragment = new AddPointsFragment().newInstance(position + 1, "");
            break;
        case 2: // Other section
            rootFragment = new CheckPointsFragment().newInstance(position + 1, "");
            break;
        default:
            break;
    }

    // update the main primary content by replacing fragments
    FragmentManager fragmentManager = getFragmentManager();

    // clear all fragments from previous section from the back stack
    fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

    // replace all currently added fragments in container and replace with the new fragment
    // don't add to back stack since these serve as "root" fragments
    fragmentManager.beginTransaction()
            .replace(R.id.container, rootFragment, rootFragment.getClass().getName())
            .commit();
}

Code snippet for creating Frag2 in Activity.java

public void startAddPointsSuccessFragment(int sectionNumber, String cardNo, int points) {
    // Create fragment and give it its arguments
    // Since this is not a major fragment,
    // I just used its major parent fragment (AddPointsFragment)
    // section number to follow the action bar title
    AddPointsSuccessFragment addPointsSuccessFragment =
            new AddPointsSuccessFragment().newInstance(sectionNumber, cardNo, points);
    // Replace whatever is in the container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.beginTransaction()
            .replace(R.id.container, addPointsSuccessFragment)
            .addToBackStack(AddPointsSuccessFragment.class.getName())
            .commit();
}

Code snippet for creating Frag3 in Activity.java

public void onOkButtonAddPointsSuccessFragmentInteraction(int sectionNumber, String cardNo, int points) {
    int minimumPoints = 10;
    if (points < minimumPoints) {
        // Go back to previous fragment (AddPointsFragment)
        // by simulating a back press from host activity.
        this.onBackPressed();
    }
    else {
        // Create fragment and give it its arguments
        // Since this is not a major fragment,
        // I just used its major parent fragment (AddPointsFragment)
        // section number to follow the action bar title
        RedeemRewardFragment redeemRewardFragment =
                new RedeemRewardFragment().newInstance(sectionNumber, cardNo, points);
        // Replace whatever is in the container view with this fragment,
        // and add the transaction to the back stack so the user can navigate back
        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, redeemRewardFragment)
                .addToBackStack(RedeemRewardFragment.class.getName())
                .commit();
    }
}

Regarding the fragments disappearing upon change in orientation, I am still not able to come up for a possible solution yet.

Regarding the persistence of saved instance state upon change in orientation, I tried implementing onSaveInstanceState(Bundle bundle) inside Frag1 class like this:

Code snippet for AddPointsFragment.java

EditText cardNoEditText;    

@Override
public void onSaveInstanceState(Bundle bundle) {
    super.onSaveInstanceState(bundle);
    bundle.putInt(ARG_SECTION_NUMBER, mSectionNumber);
    bundle.putString(ARG_CARD_NO, cardNoEditText.getText().toString());
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mSectionNumber = getArguments().getInt(ARG_SECTION_NUMBER);
        mCardNo = getArguments().getString(ARG_CARD_NO);
    }
    if (savedInstanceState != null) {
        mSectionNumber = savedInstanceState.getInt(ARG_SECTION_NUMBER);
        mCardNo = savedInstanceState.getString(ARG_CARD_NO);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_add_points, container, false);
    cardNoEditText = (EditText) view.findViewById(R.id.cardNoEditText);
    cardNoEditText.setText(mCardNo);
    Button enterCardNoButton = (Button) view.findViewById(R.id.enterCardNoButton);
    enterCardNoButton.setOnClickListener(this);
    Button scanCardNoButton = (Button) view.findViewById(R.id.scanCardNoButton);
    scanCardNoButton.setOnClickListener(this);
    return view;
}

I tried running the debugger in the code regarding the failed persistence during change of orientation, and upon inspection the onSaveInstanceState(Bundle bundle) does work and is able to pass the data to the EditText. However, I also found that the Activity also calls the onNavigationDrawerItemSelected(int position) when changing orientation, which as you can see in the code inside it, wipes the FragmentManager of Frag1 and replaces it with a new Frag1 that does not have a value of cardNo yet.

I guess the underlying question here would be what is the best way of implementing onSaveInstanceState(Bundle bundle) in this scenario? I tried implementing it inside the Fragments but I may have made a mistake? Or should I implement it in the Activity like saving an instance of the existing fragments?

Thanks in advance to those who will answer. :)

very rough idea

in oncreate ?? or oncreateview ???

   if(savedInstanceState == null){

        }else{

  int positionx = savedInstanceState.getInt("myposition"); //setfragment myposition ??!!??!!??
  myEdittext.setText(savedInstanceState.getString("myedittext")); //set text to edittext ??!!??!!??!!

    }

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.

  savedInstanceState.putInt("myposition", position);
  savedInstanceState.putString("myedittext", myEdittext.getText().toString());

}


@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.

  int positionx = savedInstanceState.getInt("myposition"); //setfragment myposition ??!!??!!??
  myEdittext.setText(savedInstanceState.getString("myedittext")); //set text to edittext ??!!??!!??!!

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM