0

I'm trying to do a simple android application with 2 fragments. First fragment is to enter the message, second fragment is to display the message.

I need to show one fragment at a time in portrait mode, both fragments in landscape mode. For that I have 2 layout files for the main activity, one for portrait(normal) mode with empty FrameLayout, second one for landscape mode with both fragments are embedded in the xml layout itself.

When I rotate the screen to landscape mode, I see that the "onCreateView()" method called twice for the first fragment.

I could not figure out how to fix this. Any thought on this would be helpful for me !!

I have already went through the same questions here in stackoverflow, but it didn't help as those questions are with viewPager, tabs, adapters.

Further details:

MainActivity.java

public class MainActivity extends Activity implements MyFragment1.MyFragment1Interface{
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState){
        Log.d(TAG,"On create called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(findViewById(R.id.my_fragment_container) != null){
            if(savedInstanceState != null)
                return;
            Log.d(TAG,"creating fragment1 and adding");
            MyFragment1 myFragment1 = new MyFragment1();
        getFragmentManager().beginTransaction().add(R.id.my_fragment_container,myFragment1).commit();
        }
    }
    @Override
    public void showMessage(String message) {
        MyFragment2 myFragment2 = (MyFragment2) getFragmentManager().findFragmentById(R.id.fragment2);
        if(myFragment2 != null)
            myFragment2.displayMessage(message);
        else{
            myFragment2 = new MyFragment2();
            Bundle args = new Bundle();
            args.putString(MyFragment1.ARG_MESSAGE,message);
            myFragment2.setArguments(args);
            getFragmentManager().beginTransaction().replace(R.id.my_fragment_container,myFragment2).addToBackStack(null).commit();
        }
    }
}

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

res/layout-land/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment android:name="com.example.emanickam.sampleapp.MyFragment1"
    android:id="@+id/fragment1"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="match_parent"/>
<fragment android:name="com.example.emanickam.sampleapp.MyFragment2"
    android:id="@+id/fragment2"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="match_parent"/>
</LinearLayout>

MyFragment1.java

public class MyFragment1 extends Fragment {
    MyFragment1Interface mMyFragment1Interface;
    public static final String ARG_MESSAGE = "arg.message";
    private static final String TAG = "MyFragment1";

    public interface MyFragment1Interface
    {
        public void showMessage(String message);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_my_fragment1, container, false);
        Button button = (Button) view.findViewById(R.id.send_message);

        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendMessage(v);
            }
        });

        Log.d(TAG,"oncreatview is called");
        return view;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mMyFragment1Interface = (MyFragment1Interface) context;

    }

    public void sendMessage(View view)
    {
        EditText message = (EditText) getActivity().findViewById(R.id.message);
        mMyFragment1Interface.showMessage(message.getText().toString());
    }
}

MyFragment2.java

public class MyFragment2 extends Fragment {
    public static final String ARG_MESSAGE = "arg.message";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_my_fragment2, container, false);
        if(getArguments() != null) {
            TextView displayMessage = (TextView) view.findViewById(R.id.display_message);
            displayMessage.setText(getArguments().getString(ARG_MESSAGE));
        }
        return view;
    }

    public void displayMessage(String message)
    {
        TextView displayMessage = (TextView) getActivity().findViewById(R.id.display_message);
        displayMessage.setText(message);
    }
}

res/layout/fragment_my_fragment1.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<EditText 
    android:id="@+id/message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:hint="Enter a message" />

<Button 
    android:id="@+id/send_message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Send Message"/>

</LinearLayout>

res/layout/fragment_my_fragment2.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/display_message"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</FrameLayout>

Logs:

> D/MainActivity: On create called 
> D/MainActivity: creating fragment1 and adding
> D/MyFragment1: oncreatview is called
 --screen rotated to landscape here 
> D/MainActivity: On create called 
> D/MyFragment1: oncreatview is called 
> D/MyFragment1: oncreatview is called

Update:

I have got few links of suggested answers to look into for same kind of question. for instance, the answer for the following stackoverflow question,

Android Orientation changes calls onCreate

suggests that we need to add the configChanges attribute in the activity in the manifest file.

 <activity android:name=".MainActivity" android:configChanges="keyboardHidden|orientation|screenSize">

This means that android system will not handle the orientation changes and the activity will handle it by itself. When I used this, the layout file I have defined for landscape mode (res/layout-land/activity_main.xml) is completely ignored and it took the portrait layout file in the landscape mode also which is completely different from what i'm trying to achieve. of-course, I understand why. this is because of the android:configChanges attribute. But this is not my intention.

I don't want to disable the android's screen rotation handling for my activity. I'm OK with the default behavior of destroying the activity and recreating it when rotation happens as I can store and retrieve necessary data to handle the destruction. I only want to know how to fix this problem of fragment onCreateView() called twice without disabling the rotation handling as per this Answer by user hackbod

Community
  • 1
  • 1
Elangovan Manickam
  • 413
  • 1
  • 5
  • 14
  • 1
    Possible duplicate of [Android orientation change calls onCreate](http://stackoverflow.com/questions/3097909/android-orientation-change-calls-oncreate) – crgarridos Oct 21 '16 at 14:14
  • It's because you've got two `MyFragment1`s attached to the `FragmentManager` after rotating - the one you created in `onCreate()` in portrait, and the one that's being created for you from the landscape layout. Also, you should observe what happens when you start your app in landscape, and then rotate to portrait. – Mike M. Oct 21 '16 at 14:21
  • @MikeM. I have tried to start the app in landscape and rotate to portrait. It started fine in landscape but when I rotate to portrait, the app shows empty screen. this is because of the if(savedInstanceState != null) {return} condition where savedInstanceState is not null after the rotation since the android system destroys the activity and restores it with this savedInstanceState Bundle. I also see this in logcat "W/PhoneWindow: Previously focused view reported id 2131230723 during save, but can't be found during restore". – Elangovan Manickam Oct 21 '16 at 17:16
  • Yep, you got it. If you want to avoid having an extra `MyFragment1` hanging around, you could just handle all of the `Fragment`s dynamically, rather than defining them in the layout. Or you could instead define `MyFragment1` statically in the portrait layout, exactly as it is in the landscape layout, so the same one will be used in both. Also, you should check for the existence of a `Fragment` using a `FragmentManager#findFragmentBy*()` method, rather than doing a `null` check on the `savedInstanceState` `Bundle`. – Mike M. Oct 21 '16 at 23:41

0 Answers0