5

I have one layout in two orientations - 1 landscape and 1 portrait.

/layout-land/main.xml has two fragments:

  • <fragment android:id="@+id/fragment1" .. />
  • <fragment android:id="@+id/fragment2" .. />

/layout/main.xml has only one fragment:

  • <fragment android:id="@+id/fragment1" .. />

Here's the MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    firstFragment = (FirstFragment) getFragmentManager().findFragmentById(R.id.fragment1);
    secondFragment = (SecondFragment) getFragmentManager().findFragmentById(R.id.fragment2);
}

Next, I start the MainActivity.java in landscape mode. In this case,

  • Both firstFragment and secondFragment refers to the fragments in the layout layout-land/main.xml

Then I rotate the screen to portrait mode, and the layout file layout/main.xml should be loaded. In this case,

  • firstFragment refers to the R.id.fragment1
  • secondFragment referes to a non-existant fragment. Accessing any elements inside this throws a NullPointerException. (To be more precise, secondFragment is not null here)

How this secondFragment is initialized when there's no fragment defined inside the layout?


Edit: Reason found on Android Developer Documentation at http://developer.android.com/training/basics/fragments/creating.html:

When a configuration change causes the activity hosting these fragments to restart, its new instance may use a different layout that doesn't include the same fragments as the previous layout. In this case all of the previous fragments will still be instantiated and running in the new instance. However, any that are no longer associated with a tag in the view hierarchy will not have their content view created and will return false from isInLayout(). (The code here also shows how you can determine if a fragment placed in a container is no longer running in a layout with that container and avoid creating its view hierarchy in that case.)

Vishnu Haridas
  • 7,355
  • 3
  • 28
  • 43
  • Are you sure second fragment is initialized, check if secondFragment==null – viv Oct 23 '13 at 07:33
  • @viv Yes, surely it's null-checked, and it's not null! – Vishnu Haridas Oct 23 '13 at 08:14
  • make sure proper xml is loading, try changing a background a bit, just to check, also see if you have nothing added in config parameter in manifest – viv Oct 23 '13 at 08:17
  • 1
    You can check for the orientation dynamically and load the second fragment accordingly. If you are in portrait mode then do not load the second fragment. – GrIsHu Oct 23 '13 at 08:24
  • 1
    @VishnuHaridas It will obviously throw nullpointer exception as there is not second fragment defined in portrait mode layout file. – GrIsHu Oct 23 '13 at 08:25
  • @GrIsHu I ran a debug, it points to an object, a fragment object. But if I access that object's member, it will throw NPE. But the solution that you proposed seems good for this problem. Thanks! – Vishnu Haridas Nov 22 '13 at 19:07

3 Answers3

3

You can check like below : I assume that you have Fragment1 class for the fragment you get by findFragmentById

Fragment1 frg1 =getFragmentManager().findFragmentById(R.id.FrgDetalleEvento);
boolean hayDetalle = ( frg1!= null && frg1.isInLayout());

It solved the same problem with me, hope it helpful for every of you

  • Thanks for adding an answer. Like you said, the method `frg1.isInLayout()` and checking the orientation are the best solutions so far. – Vishnu Haridas Sep 02 '15 at 18:06
2

maybe it's too late, but I leave it for future programmers with this problem, I had a similar problem and solved it this way.

Logic: Check the screen orientation, and call findViewById(R.id.fragment2) only if the screen is on landscape mode. Otherwise start a new intent to the other screen

Non working code;

@Override
public void onEventoSeleccionado(Evento e) {

    boolean hayDetalle = (getFragmentManager().findFragmentById(R.id.FrgDetalleEvento) != null);

            if(hayDetalle) {
                SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm",Locale.ENGLISH);
                Log.i("EOLog", "Hay Detalle");
                ((DetalleEventoFragment)getFragmentManager().findFragmentById(R.id.FrgDetalleEvento)).mostrarDetalle(Long.toString(e.getId()),formatter.format(e.getFecha()));
            }
            else {
                Log.i("EOLog", "No hay detalle");           
                Intent i = new Intent(this,DetalleEventoActivity.class);                                        
                Bundle b = new Bundle();
                b.putLong("IDEV", e.getId());           
                b.putLong("FECHA", e.getFecha());           
                i.putExtras(b);
                startActivity(i);
            }

}

Working code:

@Override
public void onEventoSeleccionado(Evento e) {

      int orientation = getResources().getConfiguration().orientation;

            if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
                SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm",Locale.ENGLISH);
                Log.i("EOLog", "Hay Detalle");
                ((DetalleEventoFragment)getFragmentManager().findFragmentById(R.id.FrgDetalleEvento)).mostrarDetalle(Long.toString(e.getId()),formatter.format(e.getFecha()));
            }
            else if(orientation == Configuration.ORIENTATION_PORTRAIT) {
                Log.i("EOLog", "No hay detalle");           
                Intent i = new Intent(this,DetalleEventoActivity.class);                                        
                Bundle b = new Bundle();
                b.putLong("IDEV", e.getId());           
                b.putLong("FECHA", e.getFecha());           
                i.putExtras(b);
                startActivity(i);
            }else
            {
                Log.i("EOLog", "Dispositivo erroneo");
            }

}

I hope that is helpful

Vishnu Haridas
  • 7,355
  • 3
  • 28
  • 43
Gabriel Nuñez
  • 131
  • 2
  • 13
  • That looks good! Just checking the Orientation and calling the second fragment only when the screen is in LANDSCAPE mode. Surely this will solve the issue. (But still have no idea why the fragment points to a non-existent one!) – Vishnu Haridas Nov 22 '13 at 19:02
0

please cross check the setContentView() of your activity class.

I think it should be- setContentView(R.layout.main);

Sino
  • 886
  • 7
  • 21
  • Oops, sorry for that, I changed it in the question. That was actually intented to be `R.layout.main` in the question! – Vishnu Haridas Oct 23 '13 at 07:07
  • 1
    I think you have to check screen orientation before finding the fragment 'secondFragment'. Loads the secondFragment only in landscape mode. there are function available to check the screen orientation at run time. During the orientation change the activity will be recreated and try to find both fragments. I don't know this is a right way.. Hope it will help you... – Sino Oct 23 '13 at 07:19
  • KD - An answer also proposed that solution. I think that will do good in this case. – Vishnu Haridas Nov 22 '13 at 19:10