0

I have a Fragment (SearchResultsFragment) which contains a RecyclerView. Search results are loaded into the RecyclerView (this being a series of CardViews).

When the user selects a CardView, they are taken to another fragment (EventDetailsFragment) where data from the selected card is loaded. All of this works fine, the only issue I am having now is, when the user selects the back button on their phone, the App crashes, giving me an Error that the XML file cannot be inflated.

I have a suspicion this might be something to do with my RecyclerView.

E/UncaughtException: android.view.InflateException: Binary XML file line #18: Binary XML file line #18: Error inflating class fragment

I also get this error:

Caused by: java.lang.IllegalArgumentException: Binary XML file line #18: Duplicate id 0x7f0f0159, tag null, or parent id 0x7f0f0158 with another fragment for com.google.android.gms.location.places.ui.PlaceAutocompleteFragment

Here is the code on my SearchResultsFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View currentView =  inflater.inflate(R.layout.fragment_start_search, container, false);
    resolvingError = savedInstanceState != null && savedInstanceState.getBoolean(RESOLVING_ERROR, false);
    initializeComponents(currentView);
    buildGoogleApi();
    handlePermissions();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        getDeviceSuggestedLocations();
    }
    return currentView;
}

private void initializeComponents(final View currentView) {
    searchResultsRecyclerView = (RecyclerView) currentView.findViewById(R.id.EventSearchResultsRecyclerView);
    searchResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    autoCompleteFragment = (PlaceAutocompleteFragment) getChildFragmentManager().findFragmentById(R.id.GoogleSearchFragment);
    autoCompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
        @Override
        public void onPlaceSelected(Place place) {
            currentLocation = place.getName().toString();
            selectedPlace = place;
            processSearch();
        }
        @Override
        public void onError(Status status) {
            displayMessage("Error Getting Location", status.getStatusMessage());
        }
    });

}

This is the XML File that fails to inflate when the back button is pressed:

    <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"
             tools:context="Fragments.StartSearchFragment"
            android:orientation="vertical"
            >
<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id ="@+id/SearchLinearLayout"
        android:orientation="vertical">
        <fragment
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id = "@+id/GoogleSearchFragment"
            android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"></fragment>
    </LinearLayout>
</android.support.v7.widget.CardView>
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id = "@+id/EventSearchResultsRecyclerView"
        android:layout_margin="5dp">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

EDIT: This is the Activity (MainActivity) where fragments get hotswapped - depending on what is picked:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Toolbar mainActivityToolbar;
private TextView toolbarTextView;
private ImageView toolbarImage;
private FragmentManager mgr;
private NavigationView navigationView;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private SharedPreferences activityPreferences;
private SharedPreferences appSharedPreferences;
private SharedPreferences.Editor editor;

protected void onCreate(Bundle savedInstanceState) {
    if (savedInstanceState == null) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeControls();
        loadLandingScreenFragment();
    } else {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeControls();
    }
}

public void initializeControls()
{
    mainActivityToolbar = (Toolbar) findViewById(R.id.MainActivityToolbar);
    toolbarTextView = (TextView) findViewById(R.id.MainActivityTextView);
    toolbarImage = (ImageView) findViewById(R.id.MainActivityImageView);
    drawerLayout = (DrawerLayout) findViewById(R.id.menuDrawerLayout);
    navigationView = (NavigationView) findViewById(R.id.mainActivityNavigationView);
    setSupportActionBar(mainActivityToolbar);
    getSupportActionBar().setTitle(null);
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
    drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, mainActivityToolbar, R.string
            .app_name, R
            .string
            .app_name);
    drawerLayout.setDrawerListener(drawerToggle);
    navigationView.inflateHeaderView(R.layout.navigation_menu_header);
    navigationView.inflateMenu(R.menu.athlete_navigation_menu);
    toolbarImage.setOnClickListener(this);
    appSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    activityPreferences = getSharedPreferences("iBaleka", MODE_PRIVATE);
    editor = activityPreferences.edit();
    NavigationMenuOnItemSelectedListener listener = new NavigationMenuOnItemSelectedListener
            (this);
    navigationView.setNavigationItemSelectedListener(listener);
    toolbarImage.setImageResource(R.drawable.ibaleka_logo);
    mgr = getFragmentManager();
    mapComponents();

}
public void loadLandingScreenFragment()
{
    AthleteLandingFragment landingFragment = new AthleteLandingFragment();
    FragmentTransaction transaction = mgr.beginTransaction();
    transaction.replace(R.id.MainActivityContentArea, landingFragment, "UserStats");
    transaction.addToBackStack("UserStats");
    transaction.commit();
}

private void mapComponents()
{
    View headerView = navigationView.getHeaderView(0);
    TextView athleteNameSurname = (TextView) headerView.findViewById(R.id.profileNameSurname);
    TextView emailAddress = (TextView) headerView.findViewById(R.id.profileEmailAddress);

    String nameSurname = appSharedPreferences.getString("Name", "") + " "+ appSharedPreferences.getString("Surname", "");
    athleteNameSurname.setText(nameSurname);
    emailAddress.setText(appSharedPreferences.getString("EmailAddress", "").toLowerCase());

}
@Override
protected void onPause() {
    editor.putString("ToolbarText", toolbarTextView.getText().toString());
    editor.commit();
    super.onPause();
}
protected void onResume() {
    super.onResume();
    toolbarTextView.setText(activityPreferences.getString("ToolbarText", ""));
}
@Override
public void onBackPressed() {
    if (mgr.getBackStackEntryCount() > 0) {
        mgr.popBackStack();
    } else {
        super.onBackPressed();
    }

}
Okuhle
  • 842
  • 3
  • 14
  • 31
  • The problem is how you load the fragments; you see, you have a fragment inside another fragment - you need to look into how to inflate a child fragment from a parent fragment – Eenvincible Jul 22 '16 at 22:11
  • Can you show the code of your activity (or whatever component holds the fragments in question)? I have a suspicion that you are trying to add a fragment twice, once on activity first start and once when you return to the activity. If you do add any fragments programmatically, you need to check to see if they don't already exist in the fragment manager. – N.T. Jul 22 '16 at 22:43
  • Post code of your activity. It seems that android:id = "@+id/GoogleSearchFragment" is added twice. Once in xml and another time in code. – Rafal Jul 23 '16 at 00:43
  • I have added code for my MainActivity - this is where fragments are swopped. – Okuhle Jul 23 '16 at 10:15
  • Are you sure the error is with the inflate not with the code after it – has19 Jul 23 '16 at 10:28

1 Answers1

0

With Reference to this thread on StackOverflow: Binary XML file line #26: Duplicate id, tag null, or parent id with another fragment

It turns out my problem was that I had a tag inside a fragment layout. This apparently is not possible - the solution was to change the tag into a LinearLayout tag, and Use the FragmentManager to load the PlaceAutocompleteFragment into the LinearLayout.

New XML (With the Fragment Tag Changed):

    <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"
             tools:context="Fragments.StartSearchFragment"
             android:orientation="vertical"
    >
<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id ="@+id/SearchLinearLayout"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id = "@+id/GoogleSearchFragment"
            android:orientation="vertical">
        </LinearLayout>
    </LinearLayout>
</android.support.v7.widget.CardView>
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id = "@+id/EventSearchResultsRecyclerView"
        android:layout_margin="5dp">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

Next, Use the FragmentManager to load the PlacesAutocompleteFragment:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View currentView =  inflater.inflate(R.layout.fragment_start_search, container, false);

    initializeComponents(currentView, savedInstanceState);
    resolvingError = savedInstanceState != null && savedInstanceState.getBoolean(RESOLVING_ERROR, false);
    buildGoogleApi();
    handlePermissions();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        getDeviceSuggestedLocations();
    }
    return currentView;
}

private void initializeComponents(View currentView, Bundle savedInstanceState) {
    searchResultsRecyclerView = (RecyclerView) currentView.findViewById(R.id.EventSearchResultsRecyclerView);
    searchResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    autoCompleteFragment = new PlaceAutocompleteFragment();
    autoCompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
            @Override
            public void onPlaceSelected(Place place) {
                currentLocation = place.getName().toString();
                selectedPlace = place;
                processSearch();
            }
            @Override
            public void onError(Status status) {
                displayMessage("Error Getting Location", status.getStatusMessage());
            }
        });
    FragmentManager mgr = getFragmentManager();
    FragmentTransaction transaction = mgr.beginTransaction();
    transaction.replace(R.id.GoogleSearchFragment, autoCompleteFragment, "AutoSearchFragment");
    transaction.commit();
}

Then, override the onDestroyView method:

    @Override
public void onDestroyView() {
    super.onDestroyView();
    FragmentManager manager = getActivity().getFragmentManager();
    Fragment fragment = manager.findFragmentById(R.id.GoogleSearchFragment);
    FragmentTransaction trans = manager.beginTransaction();
    trans.remove(fragment);
    trans.commit();
}
Community
  • 1
  • 1
Okuhle
  • 842
  • 3
  • 14
  • 31