Question

I cannot get my Fragment to retain its instance on an orientation change.

Activity Class

public class MyActivity extends Activity
{
   private MyFragment fragment;

   public void onCreate(Bundle savedInstanceState)
   {
       if(savedInstanceState == null)
       {
           fragment = new MyFragment();
       }

       //null pointer exception on this line of code. fragment not being retained. 
       getFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
   } 
}

Fragment Class

public class MyFragment extends Fragment
{ 
    private View view;
    private CustomListViewAdapter adapter;
    public ArrayList<HashMap<String, String>> arrHashMap;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        view = inflater.inflate(R.layout.fragment_screen, container, false);

        if(arrHashMap != null)
        {
            ListView lv = (ListView) view.findViewById(R.id.fragment_lv);
            adapter = new CustomListViewAdapter( (MyActivity)getActivity() , arrHashMap);
            lv.setAdapter(adapter);
            lv.setOnItemClickListener((MyActivity)getActivity());
        }
        else
        {
            /* some code to create arrHashMap variable

            */
            ListView lv = (ListView) view.findViewById(R.id.fragment_lv);
            adapter = new CustomListViewAdapter( (MyActivity)getActivity() , arrHashMap);
            lv.setAdapter(adapter);
            lv.setOnItemClickListener((MyActivity)getActivity());
        }

        return(view);
    }

    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);
        setRetainInstance(true);
    }
}

MyFragment is remaining null on an orientation change despite setRetainInstance(true) being set in onActivityCreated. When the MyActivity is created MyFragment is also always recreated. Also, I understand that setRetainInstance(true) is not to be used for UI fragments, however, I am not using the saved adapter or view member variables, I am only reusing the retained arrHashMap variable on an orientation change so I can recreate the adapter and change the UI.

Was it helpful?

Solution

UPDATE: I decided not to use setRetainInstance(true) at all and I solved the problem using the ObjectInputStream and ObjectOutputStream classes and saved the arrHashMap object to a file in the onSaveInstanceState(Bundle outState) method of MyActivity, and retrieved the arrHashMap object from that file in the onRestoreInstanceState(Bundle savedInstanceState) method of MyActivity. I then proceeded to set the adapter with the retrived arrHashMap object.

As an added note, I changed the arrHashMap instance variable of MyFragment to a static variable so it could be accessed from MyActivity.

Save Code:

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

    try
    {
        File f = new File( this.getDir("myDir", Context.MODE_PRIVATE), "arrHashMap");
        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(f));
        os.writeObject(MyFragment.arrHashMap);
        os.flush();
        os.close();
    }
    catch(IOException e)
    {
        return;
    }
}

Restore Code:

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

    ArrayList<HashMap<String,String>> arrHashMap;
    try
    {
        File f = new File( this.getDir("myDir", Context.MODE_PRIVATE), "arrHashMap");
        ObjectInputStream is = new ObjectInputStream(new FileInputStream(f));
        arrHashMap =  ((ArrayList<HashMap<String, String>>) is.readObject() );
        is.close();
    }
    catch (Exception e)
    {
        arrHashMap = null;
    }
    if(arrHashMap != null)
    {
        ListView lv = (ListView)findViewById(R.id.fragment_lv);
        CustomListViewAdapter adapter = new CustomListViewAdapter(this, arrHashMap);
        lv.setAdapter(adapter);
        lv.setOnItemClickListener(this);
    }
}

OTHER TIPS

kinda late and I hope this helps you in the future but your problem is with

if(savedInstanceState == null)
       {
           fragment = new MyFragment();
       }
getFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();

setRetainInstance means that when the app is rotated the fragment will not be recreated, the activity will still be recreated and will not hold a reference to it

so when the activity rotates and the savedInstanceState == null is checked it will not create the fragment and thus not have a reference to it

if you wish to go back and fix it it should go something like this (and this is off the top of my head so some errors may exists)

first create a constant string representing the fragment like so:

private static final String FRAGMENT = "myFragmentTag";

then on initialization

if (savedInstanceState == null) {
    fragment = new MyFragment();
    getFragmentManager().beginTransaction().replace(R.id.fragment_container,fragment,FRAGMENT).commit()
} else
    fragment = getFragmentManager().findFragmentByTag(FRAGMENT)

basically when you create the activity you generate the fragment, and when you rotate it you get the existing fragment from the fragment manager

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top