9

I'm trying to do something I do with activities, but within a fragment. What I do is using activities:

First stop the activity restarts when rotating the device android:configChanges="keyboardHidden|orientation|screenSize"

in my activity add:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

 setContentView(R.layout.main);
}

So get the activity does not restart, but reloading the main.xml, to use the layout-land

Now I have an activity showing viewpager, which contains three fragments. Everything works properly. Detection of the rotation is in the fragments

public class FRG_map_web extends Fragment  {

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        Log.i("myLogs", "Rotation");

    }

The problem is that the fragment not use setContentView(R.layout.main); this is the code:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.frg.myFragment, null); 

I tried to use:

LayoutInflater inflater = inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

view = inflater.inflate(R.layout.frg.myFragment, null); 

...

LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

view = inflater.inflate(R.layout.frg.myFragment, null); 

...

LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );

view = inflater.inflate(R.layout.frg.myFragment, null); 

...

LayoutInflater li = LayoutInflater.from(context);

and different ways, but always without success I can not inflate properly.

Can anyone tell me how I have to do?

Thanks in advance, I appreciate the help

Regards

Sergio76
  • 3,835
  • 16
  • 61
  • 88
  • Your question is not clear at all. Are you trying to recreate the fragments after a rotation? – user May 01 '13 at 06:10
  • My intention is that after rotating the device does not restart the activity, but the onConfigurationChanged of the fragment, reload the layout xml – Sergio76 May 01 '13 at 15:30
  • 2
    You're going to run into issues with `android:configChanges` because, for the most part, you shouldn't use it. There are many types of configuration changes that you are not accounting for. `onSavedInstanceState` is your friend. – Paul Burke May 03 '13 at 13:05
  • I'm using bitmaps in the fragments that are automatically resized if the fragments reload every time you rotate the device, I have the problem of "out of memory". The first load is controlled, but not the rest (how the rotation), so I need to load only once – Sergio76 May 03 '13 at 20:38
  • 2
    Overriding `android:configChanges` because of bitmaps is a poor excuse. You have to persist the bitmaps between config changes through `onSavedInstanceState`. – Ifrit May 06 '13 at 17:39
  • @JaySoyer You cannot persists Bitmaps in Bundle. MiguelC: Seems like you have a problem with either using too many bitmaps or (more likely) memory leaks. Using configChanges in the latter case is like being a doctor which tries to cure symptoms and not the cause. – MaciejGórski May 08 '13 at 17:45
  • @MaciejGórski I never said he had to use a Bundle. Just that it needs to be persisted. Note, Bitmap implements Parcelable so I see no reason why one couldn't put it into a bundle with it's method putParcelable(); – Ifrit May 08 '13 at 18:05
  • @JaySoyer Oh, it does. I should have checked before making a fuss ;) – MaciejGórski May 08 '13 at 18:08

5 Answers5

25

If I understand correctly, you don't want to the fragment to reload on each rotation. Instead you want to relayout the views and update them with information you already have.

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Get a layout inflater (inflater from getActivity() or getSupportActivity() works as well)
    LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View newView = inflater.inflate(R.layout.frg.myFragment, null);
    // This just inflates the view but doesn't add it to any thing.
    // You need to add it to the root view of the fragment
    ViewGroup rootView = (ViewGroup) getView();
    // Remove all the existing views from the root view.
    // This is also a good place to recycle any resources you won't need anymore
    rootView.removeAllViews();
    rootView.addView(newView);
    // Viola, you have the new view setup
}

According to the documentation (getView()), getView() returns the same view that you returned from your onCreateView() but it does not. It actually return the parent of the view you returned in onCreateView() which is exactly what you need. getView() will return an instance of NoSaveStateFrameLayout, which is used specifically for Fragments as its root view.

Hope this helps.

Aswin Rajendiran
  • 3,399
  • 1
  • 21
  • 18
  • I think it's a very good solution, but I get a force close and do not know why. I put a link to the logs ul.to/arq9y8gj about the logs, I have also tried without using actionbarsherlock, the error persists – Sergio76 May 09 '13 at 10:43
  • Checking from the error log, it seems that you have an error of duplicate fragment. Check this solution http://stackoverflow.com/questions/14083950/duplicate-id-tag-null-or-parent-id-with-another-fragment-for-com-google-androi – Aswin Rajendiran May 09 '13 at 17:37
  • Thanks Worked lika a Charm – Rany Ishak May 30 '13 at 11:35
  • If you have any other layout than top left on your view, you'll need to set the layout params up again on the new view. You can get this from the previous though: `ViewGroup.LayoutParams lp = rootView.getChildAt(0).getLayoutParams(); newView.setLayoutParams(lp);` – Jamie - Fenrir Digital Ltd Mar 19 '14 at 17:54
  • I tried: View newView = inflater.inflate(R.layout.frg.myFragment, null); but got warning, so I modified the code a little: (1) I declare rootView first (2) call this instead "View newView = inflater.inflate(R.layout.my frag, rootView, false);" The end result works the same, but w/o the warning. :) – Johnny Wu Jul 08 '15 at 00:15
  • Thanks a lot, it worked like a charm ! You can simply declare `final View newView = View.inflate(getActivity(), R.layout.frg.myFragment, null);` without having an instance of a layoutInflater :) – Lilo Oct 20 '15 at 12:42
  • PS: if you are using ButterKnife, don't forget to add `ButterKnife.inject(this, newView);` – Lilo Oct 20 '15 at 13:03
15

Have you considered retaining your fragment instances? See Fragment#setRetainInstance.

Allow your Activity to be recreated (do not specify android:configChanges) but retain your fragment instances across orientation changes. If all the heavy lifting happens in Fragment#onCreate this should work fine. onCreate() will not be called again since the fragment is not being re-created.

devconsole
  • 7,875
  • 1
  • 34
  • 42
  • onCreateView() gets called again to create a new view hierarchy. It should be possible to retain the Bitmaps and reuse them in the newly created views. – devconsole May 08 '13 at 20:27
3

You can try to detach e attach the fragment:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    FragmentManager fragmentManager = getFragmentManager();
    if (fragmentManager != null) {
        fragmentManager.beginTransaction().detach(this).commitAllowingStateLoss();
    }
    super.onConfigurationChanged(newConfig);
    if (fragmentManager != null) {
        fragmentManager.beginTransaction().attach(this).commitAllowingStateLoss();
    }
}
Aiuspaktyn
  • 970
  • 1
  • 13
  • 16
2

I could do it by re-attaching the fragment within onConfigurationChanged:

   @Override
   public void onConfigurationChanged(Configuration newConfig)
    {
        getActivity().detachFragment(this);

        super.onConfigurationChanged(newConfig);

        ....

        getActivity().attachFragment(this);
    }

Remember that by detaching and attaching your fragment you will be only working with its view. But the fragment state is "saved" in the Fragment manager.

Waldir Leoncio
  • 10,853
  • 19
  • 77
  • 107
TatoCuervo
  • 121
  • 6
  • 1
    Activity.[detach|attach]Fragment() methods don't exist, FragmentManager.beginTransaction().[detach|attach]() have to be used. – riot Jul 20 '17 at 06:49
0

Maybe you can try use

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.frg.myFragment, container, false);
}

. In any case, the fragment still has to be destroyed and recreated, why not let Android handle it automatically by restarting the activity? If there is any data to keep, you can save it in onSavedInstanceState(). Setting android:configChanges="keyboardHidden|orientation|screenSize" is not recommended in Android.

Neoh
  • 15,906
  • 14
  • 66
  • 78