6

I recently converted my app from an activity based app to a fragment based app. It's a score keeping app, and I was easily able to save and restore score when it was an activity. However, that doesn't seem to be working as a fragment. Here's my code:

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

    if(t!=null&&flag==1){
        savedInstanceState.putInt("time", t.getTimeLeft());
    } else {
        savedInstanceState.putInt("time", 0);
    }

    savedInstanceState.putIntArray("score_array", points);
    savedInstanceState.putIntArray("position_array", spinnerPosition);
    savedInstanceState.putBooleanArray("checked_array", shouldBeChecked);

    flag = 0;
    Log.d("MyApp", "savingState");
}

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

    Log.d("MyApp", "onActivityCreated");

    try {
        int timeLeft = savedInstanceState.getInt("time");

        points = savedInstanceState.getIntArray("score_array").clone();
        spinnerPosition = savedInstanceState.getIntArray("position_array").clone();
        shouldBeChecked = savedInstanceState.getBooleanArray("checked_array").clone();

        ((BaseAdapter) ((ListView)getView().findViewById(R.id.missionList)).getAdapter()).notifyDataSetChanged();

        if(timeLeft!=0){
            flag=1;

            this.getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

            t = new TimerClass(timeLeft*1000, 1000);
            t.setViews((TextView)getView().findViewById(R.id.minuteView), (TextView)getView().findViewById(R.id.tenSecondView), (TextView)getView().findViewById(R.id.secondView), (Button)getView().findViewById(R.id.start_button));
            ((Button)getView().findViewById(R.id.start_button)).setText(R.string.stop);
            t.start();
        }
    } catch (Exception e) {
        e.printStackTrace();
    } 

}

I used this exact same code successfully on an activity in onRestoreInstanceState rather than onActivityCreated and without the try/catch. The problem is I'm getting null pointer errors an time I try and pull something from the bundle. I can see saving state in the log, and then onActivityCreated, but onActivityCreated doesn't seem to be getting the stuff put in the bundle by onSavedInstanceState. I just get a null pointer on every line that calls savedInstanceState.getAnything(). However, from my reading, onCreate, onCreateView, and onActivityCreated all use the same bundle. I have tried moving the code to the other two with no luck.

The Holo Dev
  • 1,016
  • 3
  • 12
  • 22
  • Have you made sure that in the onSaveState method you arent saving null values in the bundle? – Marco RS Sep 18 '12 at 22:20
  • Pretty sure. They are initialized as non-null, and I'm not seeing any way for them to become null. it worked line for line as an activity. – The Holo Dev Sep 19 '12 at 03:48
  • Just checked, definitely not null. – The Holo Dev Sep 19 '12 at 03:53
  • It's difficult to say from the given code. As an alternative in the onCreate method for your fragment you can call the method "setRetainInstance(true)" and it will retain the data across orientation changes. You just have to make sure that you dont hang on to any Previous Activity references to avoid memory leaks. – Marco RS Sep 20 '12 at 08:41
  • I'll do that when I get a chance this afternoon. Can you explain further what you mean by previous activity references? Are you talking about creating multiple instances of this fragment, and setRetainInstance() will keep all of them? I already make sure I only create the fragment once, and open the same fragment every time it shows up on screen. Also, you said it's hard to tell from the given code. What other code might be helpful. I posted this because it's all the code pertaining to save/restore state. If there's anything else that would be helpful, I'll try and post it. – The Holo Dev Sep 20 '12 at 15:31
  • setRetainInstance didn't seem to do it. – The Holo Dev Sep 20 '12 at 23:15

2 Answers2

1

For anyone who needs a better answer:

Always test for if(savedInstanceState!=null) before accessing it, to avoid null pointer errors. Also, be aware that onSaveInstanceState() won't be able to save your data in all cases when your fragment is destroyed.

Particularly if your Fragment is pushed onto the back stack, and the device is rotated. In this case, only onDestoryView() gets called when your Fragment is pushed onto the back stack, so when onSaveInstanceState() runs during device rotation, it won't be able to save any data from your Views because they were all destroyed earlier.

See the following thread for a work-around. I think it's useful for everybody developing with Fragments. Especially DroidT's answer: https://stackoverflow.com/a/19744402/2517350

Community
  • 1
  • 1
0

I ended up coming up with a fairly hacky work around. Not thrilled with it, since it's not actually solving the core problem. If anyone can help me find that, I'd happy accept that answer over this.

That said, I simply used the activity's onSaveInstanceState and onRestoreInstanceState to save and restore the fragment data.

The Holo Dev
  • 1,016
  • 3
  • 12
  • 22
  • I think probably you are recreating fragments every time, please put code of how you attach this fragment to the activity. If activity is recreated it would have lost its previous fragment if added thru code on certain devices. i had the same damn problem. ended up calling setContentView(myxml) and the myxml had the fragment class in it – Pulkit Sethi Jan 20 '14 at 22:33