MrWerbenjagermanjensen MrWerbenjagermanjensen - 3 months ago 12
Android Question

Stop Infinite Loop from onCreateView when trying to load Fragment Layout

I'm trying to create an activity that loads one of two fragments. The first fragment (SendFragment) will have a textbox and a button, and will send text to the second fragment. The second fragment (DisplayFragment) will then display the text received. The MainActivity will first load the layout for SendFragment, then load the layout for DisplayFragment when the text is sent.

When the app starts, an infinite loop occurs when onCreateView() for SendFragment is called. The loop recurs between the OnCreateView() and the line to inflate the SendFragment layout.

How do I load the layout just once and stop the infinite loop?

DisplayFragment.Java

package com.example.helloworld;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link DisplayFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link DisplayFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class DisplayFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_MESSAGE = "param1";

// TODO: Rename and change types of parameters
private String message;

private OnFragmentInteractionListener mListener;

public DisplayFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @return A new instance of fragment DisplayFragment.
*/
// TODO: Rename and change types and number of parameters
public static DisplayFragment newInstance(String param1) {
DisplayFragment fragment = new DisplayFragment();
Bundle args = new Bundle();
args.putString(ARG_MESSAGE, param1);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
message = getArguments().getString(ARG_MESSAGE);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_display, container, false);
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
mListener = null;
}

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}


SendFragment.Java

package com.example.helloworld;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;


/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link SendFragment.OnMessageSentListener} interface
* to handle interaction events.
* Use the factory method to
* create an instance of this fragment.
*/
public class SendFragment extends Fragment {

private OnMessageSentListener mListener;

View view;

public SendFragment() {
// Required empty public constructor
}

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
view = inflater.inflate(R.layout.fragment_send, container, false);
return view;
}

// TODO: Rename method, update argument and hook method into UI event
public void sendMessage(View v) {

if (mListener != null) {
EditText editText = (EditText) v.findViewById(R.id.edit_message);
String message = editText.getText().toString();
mListener.onMessageSent(message);
}
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnMessageSentListener) {
mListener = (OnMessageSentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
mListener = null;
}

/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnMessageSentListener {
// TODO: Update argument type and name
void onMessageSent(String s);
}

}


MainActivity.Java

package com.example.helloworld;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;

public class MainActivity extends FragmentActivity
implements com.example.helloworld.SendFragment.OnMessageSentListener {

public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";

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

// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != null) {

// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}

// Create a new Fragment to be placed in the activity layout
SendFragment firstFragment = new SendFragment();

// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());

// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}

public void onMessageSent(String s) {

DisplayFragment display = (DisplayFragment)
getSupportFragmentManager().findFragmentById(R.id.display_fragment);

if (display != null) {

// do something??

}
else {

DisplayFragment newFragment = DisplayFragment.newInstance(s);

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

}

}
}


fragment_display.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.helloworld.DisplayFragment">

<!-- TODO: Update blank fragment layout -->
<fragment android:name="com.example.helloworld.DisplayFragment"
android:id="@+id/display_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</fragment>

</FrameLayout>


fragment_send.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.helloworld.SendFragment">


<fragment android:name="com.example.helloworld.SendFragment"
android:id="@+id/send_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<EditText android:id="@+id/edit_message"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send"
android:onClick="sendMessage" />

</LinearLayout>
</fragment>


</FrameLayout>


activity_main.xml

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

Answer

Change your onCreateView() to -

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

        return  inflater.inflate(R.layout.fragment_send, container, false);
    }

Update --

Remove <fragment> component from both of your fragments' layout. That's not required since you are already initializing your fragments dynamically.