Swipe to the right after left gives ANDROID error

Asked

Viewed 228 times

1

I am creating an application on Android in Eclipse with 3 screen with Swipe horizontal, in the last tab I have a Map Fragment.

But it turns out that when doing Swipe to the right the first time everything is normal, when doing a Swipe to the left and then going back to the right the application crashes and I get this error, which may be?

Thanks in advance

07-29 23:35:38.279: E/AndroidRuntime(10353): FATAL EXCEPTION: main
07-29 23:35:38.279: E/AndroidRuntime(10353): Process: com.sapires.JoesPizzariaGEN, PID: 10353
07-29 23:35:38.279: E/AndroidRuntime(10353): android.view.InflateException: Binary XML file line #8: Error inflating class fragment
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:719)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at com.sapires.JoesPizzaria.Mapa.onCreateView(Mapa.java:16)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1504)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:942)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:482)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:163)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.view.ViewPager.populate(ViewPager.java:1073)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.support.v4.view.ViewPager$3.run(ViewPager.java:249)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.Choreographer.doCallbacks(Choreographer.java:603)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.Choreographer.doFrame(Choreographer.java:572)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.os.Handler.handleCallback(Handler.java:733)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.os.Handler.dispatchMessage(Handler.java:95)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.os.Looper.loop(Looper.java:136)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.app.ActivityThread.main(ActivityThread.java:5579)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at java.lang.reflect.Method.invoke(Native Method)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
07-29 23:35:38.279: E/AndroidRuntime(10353): Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f070016, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.MapFragment
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.app.Activity.onCreateView(Activity.java:5002)
07-29 23:35:38.279: E/AndroidRuntime(10353):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:695)
07-29 23:35:38.279: E/AndroidRuntime(10353):    ... 25 more

Layout of Fragment Map

<?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:gravity="center"
    android:orientation="vertical">
    <fragment
        android:id="@+id/fragment"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.MapFragment" />
</LinearLayout>

Class

    package com.sapires.JoesPizzaria;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

public class TabPagerAdapter extends FragmentStatePagerAdapter {
    public TabPagerAdapter(FragmentManager fm) {
        super(fm);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Fragment getItem(int i) {
        switch (i) {
        case 0:
            return new APizzaria();
        case 1:
            return new Ementa();
        case 2:
            return new Mapa();
        }
        return null;

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return 3; //No of Tabs
    }
    }
  • Place the layout of Fragment Mapa. How are the fragments being removed and inserted? Are you sure you are not leaving two equal fragments in the Activity?

  • Include these codes by editing your question, it becomes more readable.

  • Okay, I added to the question, thank you

  • I recommend doing the following, take out the id of <fragment> and use tag. To recover the fragment, use the findFragmentByTag of FragmentManager.

  • can exemplify pf, what is tag? Thank you

  • I’ve had these problems before, and as a tag is a way to uniquely identify a fragment instance as well as the id, I have my doubts if it will resolve. The case is that the application is trying to add to Fragmentmanager two instances of Mapfragment identified in the same way, which is not allowed. It would be the case to increase offscreenPageLimit or remove Mapfragment from Fragmentmanager before adding another instance of it.

  • So how can I fix?

  • I’ll explain in a reply, Father.

  • this is the project: https://www.dropbox.com/s/7xozvj40uezkmg7/SwipeTab.rar

Show 4 more comments

1 answer

1

The error is due to LayoutInflater try to add to the Activity layout a fragment that had already been added previously (trigger exception here). The reason for this is that the FragmentStatePagerAdapter is wanting to display the same fragment twice on the screen. It does this because it is not removing the fragment from the FragmentManager when it should, because it is a fragment "son" of the fragment that is effectively removed (fragment within another fragment or nested Fragment). The "father" fragment is removed from the FragmentManager and the "son" remains. The child-fragment in question is the MapFragment included in res/layout/mapa.xml id R.id.fragment.

The mistake nay is due to the application trying to add to FragmentManager two instances of MapFragment identified in the same way, as I had previously stated.

Solution

According to this answer in Soen for the nested Fragments work the child fragment has to be added dynamically in the code instead of including it in the layout as it is being done. This excerpt from the documentation illustrates this:

Note: You cannot inflate the layout into a Fragment when that layout includes a <Fragment>. Nested Fragments are only supported when Added to a Fragment dynamically.

This means the code of the files /res/layout/mapa.xml and Mapa.java should be amended as follows (note the replacement of MapFragment for SupportMapFragment, among other amendments):

/res/layout/mapa.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

</RelativeLayout>

Mapa.java

package com.sapires.JoesPizzaria;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.maps.SupportMapFragment;
import com.sapires.JoesPizzariaGEN.R;

public class Mapa extends Fragment {

    private SupportMapFragment mFragmentoDoMapa;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View windows = inflater.inflate(R.layout.mapa, container, false);
        return windows;
    }

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

        mFragmentoDoMapa = SupportMapFragment.newInstance();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.container, mFragmentoDoMapa);
        ft.commit();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        getFragmentManager().beginTransaction().remove(mFragmentoDoMapa).commit();
    }
}

Note however that this adds Flicker when the user goes to the map tab, that is, the screen flashes "due to the sudden addition of SupportMapFragment to the layout. To solve this, do the ViewPager instantiate only once the fragments created for each tab and preserve those instances between screen changes by adding the line Tab.setOffscreenPageLimit(2); to class MainActivity.java:

Tab.setAdapter(TabAdapter);
Tab.setOffscreenPageLimit(2);

Another possible solution

You can remove the instance from MapFragment of FragmentManager together with the destruction of the fragment Mapa. A place where this can be done is just before the line return new Mapa();, do as you are doing in Mapa to remove the fragment with id R.id.fragment. Another place where this can be done is in one of the methods Mapa.onDestroyView(), Mapa.onDetach() or Mapa.onDestroy() (the latter is the most appropriate).

  • Sorry I couldn’t understand, I already changed the map.onDestroyView() by Mapa.onDetach() and it’s still the same, the rest of the explanation is very complicated for me...

  • @Piovezan, it’s very strange this... looking at the source code of FragmentStatePagerAdapter (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/support/v4/app/FragmentStatePagerAdapter.java). He should take the Fragment before adding another. In the project layouts he has no id repeated not?

  • @What do you not understand? The method Tab.setOffscreenPageLimit(3); may be called in MainActivity, for example below the line Tab.setAdapter(TabAdapter);. As an alternative to Tab.setOffscreenPageLimit(3) you can move the code from Mapa.onDestroyView() for MainActivity, placing it immediately above the line return new Mapa();. Another thing (a third alternative) about the orientation of moving the code to onDetach(), try to move to Mapa.onDestroy(), maybe it works.

  • @Wakim There is no id not repeated, the case is that the Adapter even removes the fragment "father", but there is a fragment "son" (fragment within another fragment) that it does not remove, which is the MapFragment stated in map.xml. This "son" fragment is created and added to the FragmentManager implicitly when the parent fragment Mapa is created on line return new Mapa();, and is not removed at any time.

  • I would recommend taking the ids and use the tag, perhaps the FragmentManager is getting lost in relation to the removal of Fragments. And I recommend not calling the methods onDetach and onDestroyView manually. These methods are called according to the life cycle of the Fragment.

  • These methods are not being called manually. It is that within them there is code that removes the id fragment R.id.fragment (this fragment "son"), is the code that I refer to.

  • @Wakim In what part of the code will @Sapires be able to use tags? Who adds the fragments to the FragmentManager is the FragmentStatePagerAdapter implicitly and using id, not the application code.

  • I get the idea but I always get errors :( it is possible to edit the project of https://www.dropbox.com/s/7xozvj40uezkmg7/SwipeTab.rar THANK YOU VERY MUCH

  • @Sorry Sapires, but the purpose of the site is not to throw the code in the hands of others and expect them to solve the problem for you. There has to be effort on your part too. If you are encountering problems, add them to your question or comments and participate in solving them. If an explanation is not clear enough, ask.

  • You’re right, I finally did, I created this method: @Override public void onDestroyView() { super.onDestroyView(); Fragment f = getFragmentManager(). findFragmentById(R.id.mapFragment); if (f != null) getFragmentManager(). beginTransaction(). remove(f). commit(); }

  • Did this solve the problem? Something else, I took advantage and corrected the explanation of the problem in my answer, which was incorrect.

  • Yes solved my problem, ie need to "clear" the map before loading again with Swipe

  • @Sapires, as this answer solved your problem, I recommend that you mark the answer as correct, so others will orient themselves better and prevent other people from thinking that the problem has not been solved.

  • @Sapires I detailed a better solution in my reply, recommend using it. If it is ok for you, accept the answer as explained here.

Show 9 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.