Handling orientation changes with Fragments

2019-01-26 16:27发布

I'm currently testing my app with a multipane Fragment-ised view using the HC compatibility package, and having a lot of difficultly handling orientation changes.

My Host activity has 2 panes in landscape (menuFrame and contentFrame), and only menuFrame in portrait, to which appropriate fragments are loaded. If I have something in both panes, but then change the orientation to portrait I get a NPE as it tries to load views in the fragment which would be in the (non-existent) contentFrame. Using the setRetainState() method in the content fragment didn't work. How can I sort this out to prevent the system loading a fragment that won't be shown?

Many thanks!

3条回答
走好不送
2楼-- · 2019-01-26 16:32

Create new Instance only for First Time.

This does the trick:
Create a new Instance of Fragment when the activity start for the first time else reuse the old fragment.
How can you do this?
FragmentManager is the key

Here is the code snippet:

if(savedInstanceState==null) {
    userFragment = UserNameFragment.newInstance();
    fragmentManager.beginTransaction().add(R.id.profile, userFragment, "TAG").commit();
}
else {
    userFragment = fragmentManager.findFragmentByTag("TAG");
}

Save data on the fragment side

If your fragment has EditText, TextViews or any other class variables which you want to save while orientation change. Save it onSaveInstanceState() and Retrieve them in onCreateView() method

Here is the code snippet:

// Saving State

@Override
public void onSaveInstanceState(Bundle outState) {
     super.onSaveInstanceState(outState);
     outState.putString("USER_NAME", username.getText().toString());
     outState.putString("PASSWORD", password.getText().toString());
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

     View view = inflater.inflate(R.layout.user_name_fragment, parent, false);

     username = (EditText) view.findViewById(R.id.username);
     password = (EditText) view.findViewById(R.id.password);


     // Retriving value

     if (savedInstanceState != null) {
         username.setText(savedInstanceState.getString("USER_NAME"));
         password.setText(savedInstanceState.getString("PASSWORD"));
     }

     return view;
}

You can see the full working code HERE

查看更多
在下西门庆
3楼-- · 2019-01-26 16:51

It seems that the onCreateViewMethod was causing issues; it must return null if the container is null:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {   
    if (container == null) // must put this in
        return null;
    return inflater.inflate(R.layout.<layout>, container, false);
}
查看更多
可以哭但决不认输i
4楼-- · 2019-01-26 16:54

Probably not the ideal answer but if you have contentFrame for portrait and in your activity only load up the menuFrame when the savedInstanceState is null then your content frame fragments will be shown on an orientation change.

Not ideal though as then if you hit the back button (as many times as necessary) then you'll never see the menu fragment as it wasn't loaded into contentFrame.

It is a shame that the FragmentLayout API demos doesn't preserve the right fragment state across an orientation change. Regardless, having thought about this problem a fair bit, and tried out various things, I'm not sure that there is a straightforward answer. The best answer that I have come up with so far (not tested) is to have the same layout in portrait and landscape but hide the menuFrame when there is something in the detailsFrame. Similarly show it, and hide frameLayout when the latter is empty.

查看更多
登录 后发表回答