Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragment in viewpager savedinstancestate is always null

I know this question has been asked before but none of the answers given so far is of any help to me.

I have a viewpager which is populated with fragments (android.support.v4.app.Fragment) from a FragmentStatePagerAdapter . Some of these fragments contain logic that needs to be retained when the orientation changes, such as keeping track of which view is currently selected.

However, although I save the data in question in onSaveInstanceState the savedInstanceState is always null. I can solve this by storing the data in a static variable (which since I only have one instance of each fragment would work for me) but i found this to be a quite ugly solution and there has to be a proper way of doing this.

This is one of the fragments that doesn't retain it's state on rotation:

    public class PriceSelectFragment extends Fragment {

    private TableRow mSelected;
    private int mSelectedPos = 0;

    // newInstance constructor for creating fragment with arguments
    public static PriceSelectFragment newInstance() {
        PriceSelectFragment fragmentFirst = new PriceSelectFragment();
        return fragmentFirst;
    }

    public PriceSelectFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_price_select, container, false);
        TableLayout mTable = (TableLayout)view.findViewById(R.id.price_table);

        List<PriceGroup> mPriceGroups = ((MainActivity) getActivity()).getPriceGroups();

        int i = 0;
        for (final PriceGroup group : mPriceGroups) {
            //Create row from layout and access child TextViews
            TableRow r = (TableRow)inflater.inflate( R.layout.price_group, mTable, false);
            TextView size = (TextView)r.getChildAt(0);
            TextView dimension = (TextView)r.getChildAt(1);
            TextView weight = (TextView)r.getChildAt(2);
            TextView price = (TextView)r.getChildAt(3);

            //Populate row with PriceGroup Data
            size.setText(group.sizeIndicator);
            dimension.setText(String.format("%2.0fx%2.0fx%2.0f", group.length, group.width, group.height));
            weight.setText(Float.toString(group.weight));
            price.setText(Integer.toString(group.price));

            //Alternate background color every other row
            if (i % 2 == 0) {
                r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
            }
            else {
                r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
            }
            mTable.addView(r); // Add to table

            r.setTag(i);
            r.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    selectRow((TableRow) v);
                }
            });
            i++;
        }

        mSelected = (TableRow)view.findViewWithTag(mSelectedPos);
        selectRow(mSelected);

        return view;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("selected", mSelectedPos);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) {
            mSelectedPos = savedInstanceState.getInt("selected");
        }
    }

    private void selectRow(TableRow row) {
        if ((int) mSelected.getTag() % 2 == 0) {
            mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
        }
        else {
            mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
        }
        mSelected = row;
        mSelectedPos = (int) mSelected.getTag();
        mSelected.setBackgroundColor(getResources().getColor(R.color.light_blue));
    }


}

How do I solve this without having to save my states in static variables?

Edit

I should point out that all of the fragments are programatically created and as such they do not have an id and I read that that might be the problem but I don't know how to solve that either.

Also my application is structured like this:

  • MainActivity with NavigationDrawer
    • Fragment1
      • ViewPager
        • subfragment1 - subfragment5
    • Fragment2
    • Fragment3

The fragments whose states I'm having trouble with are the subfragments.

like image 793
Nobbe Avatar asked Apr 29 '15 13:04

Nobbe


People also ask

Why is savedInstanceState null?

If there is no available instance data, the savedInstanceState will be null.

Is ViewPager deprecated?

This method may be called by the ViewPager to obtain a title string to describe the specified page. This method is deprecated. This method should be called by the application if the data backing this adapter has changed and associated views should update.

What is ViewPager in Java?

ViewPager in Android allows the user to flip left and right through pages of data. In our android ViewPager application we'll implement a ViewPager that swipes through three views with different images and texts.

Can we add activity in ViewPager?

You can't use ViewPager to swipe between Activities . You need to convert each of you five Activities into Fragments , then combine everything in one FragmentActivity with the Adapter you use with ViewPager .


1 Answers

In your Activity which is hosting your Fragment you need to store a refernce to the fragment in the Bundle.

Something like this should work for you

public void onCreate(Bundle savedInstanceState) {

    if (savedInstanceState != null) {
        //Restore your fragment instance
        fragment1 = getSupportFragmentManager().getFragment(
                    savedInstanceState, "fragment");
    }
}


protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    getSupportFragmentManager().putFragment(outState, "fragment", fragment1);
}

fragment1 is the instance of the Fragment1 that you mentioned in your question that needs to get recreated.

I haven't done this with a structure like yours before but this is how I would start:

In the onSaveInstanceState in your Fragment1 I believe you would need to do the same with each of the fragments in your ViewPager. Then in the onCreateView on your Fragment1 get the fragments from the fragment manager and recreate your ViewPager.

I have found this answer here which is pretty much the same but has a little more detail: https://stackoverflow.com/a/17135346/1417483

like image 166
Dreagen Avatar answered Oct 11 '22 09:10

Dreagen