Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fool-proof way to handle Fragment on orientation change

public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager
            .beginTransaction();

    // add menu fragment
    MainMenuFragment myFragment = new MainMenuFragment();
    fragmentTransaction.add(R.id.menu_fragment, myFragment);

    //add content
    DetailPart1 content1= new DetailPart1 ();
    fragmentTransaction.add(R.id.content_fragment, content1);
    fragmentTransaction.commit();

}
public void onMainMenuSelected(String tag) {
  //next menu is selected replace existing fragment
}

I have a need to display two list views side by side, menu on left and its content on right side. By default, the first menu is selected and its content is displayed on right side. The Fragment that displays content is as below:

public class DetailPart1 extends Fragment {
  ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
  ListAdapter adap;
  ListView listview;

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

       if(savedInstanceState!=null){
        myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
        adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
        listview.setAdapter(adap);
       }else{
        //get list and load in list view
        getlistTask = new GetALLListTasks().execute();
    }


     @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.skyview_fragment, container,false);
           return v;
        }


     @Override
      public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
          outState.putSerializable("MYLIST_obj", myList );
        }
    }

The onActivityCreated and onCreateView are called twice. There are many examples out there using fragments. Since I am beginner in this subject, I am unable relate the example with my problem. I need a fool proof way to handle orientation change. I have NOT declared android:configChanges in manifest file. I need the activity destroy and recreate so that I can use different layout in landscape mode.

like image 737
user1811741 Avatar asked Nov 09 '12 10:11

user1811741


People also ask

How to handle changes in screen orientation?

If you want to manually handle orientation changes in your app you must declare the "orientation" , "screenSize" , and "screenLayout" values in the android:configChanges attributes. You can declare multiple configuration values in the attribute by separating them with a pipe | character.

How do you stop a fragment from recreating?

Calling setRetainInstance(true) will prevent the Fragment from being re-created. But, right now the Activity is always re-creating the DrawerFragment and forcefully re-creating the HomeFragment , resulting in the behavior you are seeing. In your Activity. onCreate() check the savedInstanceState is null .

What happens when screen orientation changes in Android?

When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them. Android does this so that your application can reload resources based on the new configuration.


2 Answers

You are creating a new fragment every time you turn the screen in your activity onCreate(); But you are also maintaining the old ones with super.onCreate(savedInstanceState);. So maybe set tag and find the fragment if it exists, or pass null bundle to super.

This took me a while to learn and it can really be a pain when you are working with stuff like viewpager.

I'd recommend you to read about fragments an extra time as this exact topic is covered.

Here is an example of how to handle fragments on a regular orientation change:

Activity:

public class MainActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (savedInstanceState == null) {
            TestFragment test = new TestFragment();
            test.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
        } else {
            TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
        }
    }
}

Fragment:

public class TestFragment extends Fragment {

    public static final String KEY_ITEM = "unique_key";
    public static final String KEY_INDEX = "index_key";
    private String mTime;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        
        if (savedInstanceState != null) {
            // Restore last state
            mTime = savedInstanceState.getString("time_key");
        } else {
            mTime = "" + Calendar.getInstance().getTimeInMillis();
        }
        
        TextView title = (TextView) view.findViewById(R.id.fragment_test);
        title.setText(mTime);
        
        return view;
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("time_key", mTime);
    }
}
like image 164
Warpzit Avatar answered Oct 24 '22 14:10

Warpzit


A good guideline about how to retain data between orientation changes and activity recreation can be found in android guidelines.

Summary:

  1. make your fragment retainable:

    setRetainInstance(true);
    
  2. Create a new fragment only if necessary (or at least take data from it)

    dataFragment = (DataFragment) fm.findFragmentByTag("data");
    
    // create the fragment and data the first time
    if (dataFragment == null) {
    
like image 45
Sergej Werfel Avatar answered Oct 24 '22 13:10

Sergej Werfel