Dupliceer ID, tag null of ouder-ID met een ander fragment voor com.google.android.gms.maps.MapFragment

Ik heb een applicatie met drie tabbladen.

Elk tabblad heeft zijn eigen lay-out .xml-bestand. De main.xml heeft zijn eigen kaartfragment. Het is degene die verschijnt wanneer de applicatie voor het eerst wordt gestart.

Alles werkt prima, behalve wanneer ik wissel tussen tabbladen. Als ik probeer terug te schakelen naar het kaartfragment-tabblad, krijg ik deze foutmelding. Overschakelen naar en tussen andere tabbladen werkt prima.

Wat kan hier mis zijn?

Dit is mijn hoofdklasse en mijn main.xml, evenals een relevante klasse die ik gebruik (je vindt ook het foutenlogboek onderaan)

hoofdklas

package com.nfc.demo;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.Toast;
public class NFCDemoActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActionBar bar = getActionBar();
        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
        bar.addTab(bar
                .newTab()
                .setText("Map")
                .setTabListener(
                        new TabListener<MapFragment>(this, "map",
                                MapFragment.class)));
        bar.addTab(bar
                .newTab()
                .setText("Settings")
                .setTabListener(
                        new TabListener<SettingsFragment>(this, "settings",
                                SettingsFragment.class)));
        bar.addTab(bar
                .newTab()
                .setText("About")
                .setTabListener(
                        new TabListener<AboutFragment>(this, "about",
                                AboutFragment.class)));
        if (savedInstanceState != null) {
            bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        }
        // setContentView(R.layout.main);
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    }
    public static class TabListener<T extends Fragment> implements
            ActionBar.TabListener {
        private final Activity mActivity;
        private final String mTag;
        private final Class<T> mClass;
        private final Bundle mArgs;
        private Fragment mFragment;
        public TabListener(Activity activity, String tag, Class<T> clz) {
            this(activity, tag, clz, null);
        }
        public TabListener(Activity activity, String tag, Class<T> clz,
                Bundle args) {
            mActivity = activity;
            mTag = tag;
            mClass = clz;
            mArgs = args;
            // Check to see if we already have a fragment for this tab,
            // probably from a previously saved state. If so, deactivate
            // it, because our initial state is that a tab isn't shown.
            mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
            if (mFragment != null && !mFragment.isDetached()) {
                FragmentTransaction ft = mActivity.getFragmentManager()
                        .beginTransaction();
                ft.detach(mFragment);
                ft.commit();
            }
        }
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            if (mFragment == null) {
                mFragment = Fragment.instantiate(mActivity, mClass.getName(),
                        mArgs);
                ft.add(android.R.id.content, mFragment, mTag);
            } else {
                ft.attach(mFragment);
            }
        }
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            if (mFragment != null) {
                ft.detach(mFragment);
            }
        }
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT)
                         .show();
        }
    }
}

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="vertical" >
    <fragment
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapFragment"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

relevante klasse ( MapFragment.java )

package com.nfc.demo;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MapFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.main, container, false);
    }
    public void onDestroy() {
        super.onDestroy();
    }
}

fout

android.view.InflateException: Binary XML file line #7: 
     Error inflating class fragment
   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
   at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
   at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
   at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
   at com.nfc.demo.MapFragment.onCreateView(MapFragment.java:15)
   at android.app.Fragment.performCreateView(Fragment.java:1695)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)
   at android.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1255)
   at android.app.BackStackRecord.run(BackStackRecord.java:672)
   at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435)
   at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441)
   at android.os.Handler.handleCallback(Handler.java:725)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:5039)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
   at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: 
     Binary XML file line #7: Duplicate id 0x7f040005, tag null, or 
     parent id 0xffffffff with another fragment for 
     com.google.android.gms.maps.MapFragment
   at android.app.Activity.onCreateView(Activity.java:4722)
   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)
   ... 19 more

Antwoord 1, autoriteit 100%

Het antwoord dat Matt suggereert werkt, maar zorgt ervoor dat de kaart opnieuw wordt gemaakt en opnieuw wordt getekend, wat niet altijd wenselijk is.
Na veel vallen en opstaan, heb ik een oplossing gevonden die voor mij werkt:

private static View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (view != null) {
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent != null)
            parent.removeView(view);
    }
    try {
        view = inflater.inflate(R.layout.map, container, false);
    } catch (InflateException e) {
        /* map is already there, just return view as it is */
    }
    return view;
}

Voor de goede orde, hier is “map.xml” (R.layout.map) met R.id.mapFragment (android:id=”@+id/mapFragment”):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>

Ik hoop dat dit helpt, maar ik kan niet garanderen dat het geen nadelige effecten heeft.

Bewerken:Er waren enkele nadelige effecten, zoals bij het afsluiten van de applicatie en het opnieuw starten ervan. Aangezien de applicatie niet per se volledig is afgesloten (maar gewoon op de achtergrond in de sluimerstand wordt gezet), mislukt de vorige code die ik heb ingediend bij het opnieuw opstarten van de applicatie. Ik heb de code bijgewerkt naar iets dat voor mij werkt, beide gaan in & uit de kaart te halen en de applicatie te verlaten en opnieuw te starten, ben ik niet zo blij met het try-catch-bit, maar het lijkt goed genoeg te werken. Toen ik naar de stacktrace keek, bedacht ik me dat ik gewoon kon controleren of het kaartfragment in de FragmentManager staat, geen try-catch-blok nodig, code bijgewerkt.

Meer bewerkingen:het blijkt dat je die try-catch toch nodig hebt. Alleen het zoeken naar het kaartfragment bleek toch niet zo goed te werken. Blergh.


Antwoord 2, autoriteit 71%

Het probleem is dat wat je probeert te doen niet gedaan moet worden. Je moet geen fragmenten opblazen in andere fragmenten. Uit de documentatievan Android:

Opmerking: u kunt een lay-out niet opblazen tot een fragment wanneer die lay-out
bevat een <fragment>. Geneste fragmenten worden alleen ondersteund als ze zijn toegevoegd
dynamisch naar een fragment.

Hoewel je de taak misschien kunt volbrengen met de hier gepresenteerde hacks, raad ik je ten zeerste aan om het niet te doen. Het is onmogelijk om er zeker van te zijn dat deze hacks aankunnen wat elk nieuw Android-besturingssysteem doet wanneer je probeert een lay-out op te blazen voor een fragment dat een ander fragment bevat.

De enige door Android ondersteunde manier om een ​​fragment aan een ander fragment toe te voegen, is via een transactie van de onderliggende fragmentmanager.

Verander eenvoudig uw XML-lay-out in een lege container (voeg indien nodig een ID toe):

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

Vervolgens in de Fragment onViewCreated(View view, @Nullable Bundle savedInstanceState)methode:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    FragmentManager fm = getChildFragmentManager();
    SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentByTag("mapFragment");
    if (mapFragment == null) {
        mapFragment = new SupportMapFragment();
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(R.id.mapFragmentContainer, mapFragment, "mapFragment");
        ft.commit();
        fm.executePendingTransactions();
    }
    mapFragment.getMapAsync(callback);
}

Antwoord 3, autoriteit 46%

Ik had hetzelfde probleem en kon het oplossen door handmatig het MapFragmentte verwijderen in de onDestroy()methode van de Fragmentklasse . Hier is code die werkt en verwijst naar het MapFragmentop ID in de XML:

@Override
public void onDestroyView() {
    super.onDestroyView();
    MapFragment f = (MapFragment) getFragmentManager()
                                         .findFragmentById(R.id.map);
    if (f != null) 
        getFragmentManager().beginTransaction().remove(f).commit();
}

Als u niet de MapFragmenthandmatig, het zal hangen rond, zodat het niet veel van de middelen om te recreëren kost / tonen de kaartweergave weer. Het schijnt dat het houden van het onderliggende MapViewis zeer geschikt voor heen en weer schakelen tussen de lippen, maar bij gebruik in fragmenten zorgt dit ervoor dat een duplicaat MapViewwordt gecreëerd bij elke nieuwe MapFragmentmet dezelfde ID. De oplossing is om de MapFragmenthandmatig verwijderen en zo opnieuw de onderliggende kaart telkens wanneer het fragment wordt opgeblazen.

I merkte ook dit in een ander antwoord [1 ].


4, Autoriteit 6%

Dit is mijn antwoord:

1, Maak een lay-out xml als volgt:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

2, in het Fragment klasse, voeg een google map programmatisch.

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
 * A simple {@link android.support.v4.app.Fragment} subclass. Activities that
 * contain this fragment must implement the
 * {@link MapFragment.OnFragmentInteractionListener} interface to handle
 * interaction events. Use the {@link MapFragment#newInstance} factory method to
 * create an instance of this fragment.
 * 
 */
public class MapFragment extends Fragment {
    // TODO: Rename parameter arguments, choose names that match
    private GoogleMap mMap;
    @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
        View view = inflater.inflate(R.layout.fragment_map, container, false);
        SupportMapFragment mMapFragment = SupportMapFragment.newInstance();
        mMap = mMapFragment.getMap();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.add(R.id.map_container, mMapFragment).commit();
        return view;
    }
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d("Attach", "on attach");
    }
    @Override
    public void onDetach() {
        super.onDetach();
    }
} 

5, Autoriteit 2%

  1. Zoals door @Justin Breitfeller, @Vidar Wahlberg oplossing is een hack die misschien niet werken in toekomstige versies van Android.
  2. @Vidar Wahlberg perfer een hack omdat andere oplossing zou kunnen “dat de kaart opnieuw worden gemaakt en opnieuw getekend, wat niet altijd wenselijk is”. Kaart opnieuw tekenen kan worden voorkomen door het behoud van de oude kaart fragment, in plaats van het creëren van een nieuwe instantie elke keer weer.
  3. @Matt oplossing niet werkt voor mij (IllegalStateException)
  4. Zoals geciteerd door @Justin Breitfeller, “Je kunt niet opblazen een lay-out in een fragment wanneer die lay-out is voorzien van een. Geneste fragmenten worden alleen ondersteund wanneer toegevoegd aan een fragment dynamisch.”

Mijn oplossing:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,                              Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_map_list, container, false);
    // init
    //mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map);
    // don't recreate fragment everytime ensure last map location/state are maintain
    if (mapFragment == null) {
        mapFragment = SupportMapFragment.newInstance();
        mapFragment.getMapAsync(this);
    }
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    // R.id.map is a layout
    transaction.replace(R.id.map, mapFragment).commit();
    return view;
}

Antwoord 6, autoriteit 2%

SupportMapFragment-object globaal declareren

   private SupportMapFragment mapFragment;

In de methode onCreateView() onder de code zetten

mapFragment = (SupportMapFragment) getChildFragmentManager()
            .findFragmentById(R.id.map);
 mapFragment.getMapAsync(this);

Plaats in onDestroyView() onderstaande code

@Override
public void onDestroyView() {
   super.onDestroyView();
    if (mapFragment != null)
        getFragmentManager().beginTransaction().remove(mapFragment).commit();
}

Plaats in je xml-bestand onderstaande code

<fragment
    android:id="@+id/map"
    android:name="com.abc.Driver.fragment.FragmentHome"
    class="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

Bovenstaande code heeft mijn probleem opgelost en het werkt prima


Antwoord 7

Ik zou replace()aanraden in plaats van attach()/detach()in je tabbladbehandeling.

Of schakel over naar ViewPager. Hier is een voorbeeldprojectmet een ViewPager, met tabbladen, met 10 kaarten.


Antwoord 8

Een andere oplossing:

if (view == null) {
    view = inflater.inflate(R.layout.nearbyplaces, container, false);
}

Dat is het, als het niet null is, hoeft u het niet opnieuw te initialiseren. Het verwijderen van de ouder is een onnodige stap.


Antwoord 9

Je retourneert of blaast de lay-out twee keer op, controleer gewoon of je maar één keer opblaast.


Antwoord 10

Ik heb vandaag uren verloren om de reden te vinden, gelukkig is dit probleem niet vanwege de implementatie van MapFragment, maar helaas werkt dit niet omdat geneste fragmenten alleen worden ondersteund via de ondersteuningsbibliotheek vanaf rev 11.

Mijn implementatie heeft een activiteit met een actiebalk (in tabbladen) met twee tabbladen (geen viewpager), één met de kaart en de andere met een lijst met items. Natuurlijk ben ik nogal naïef geweest om MapFragment in mijn tab-fragmenten te gebruiken, en voila de app crashte telkens als ik terugschakelde naar map-tab.

( Hetzelfde probleem zou ik ook hebben als mijn tab-fragment een lay-out zou opblazen die een ander fragment bevat ).

Eén optie is om MapView te gebruiken (in plaats van MapFragment), maar met wat overhead (zie MapView Docsals drop-in vervanging in de layout.xml, een andere optie is om de ondersteuningsbibliotheek te gebruiken vanaf rev. 11, maar dan een programmatische benadering te gebruiken sinds deze is genest fragmenten worden niet ondersteund via lay-out. Of gewoon programmatisch werken door het fragment expliciet te vernietigen (zoals in het antwoord van Matt / Vidar), trouwens: hetzelfde effect wordt bereikt met behulp van de MapView (optie 1).

Maar eigenlijk wilde ik de kaart niet verliezen telkens wanneer ik weg, dat wil zeggen, ik wilde het in het geheugen en opruimen alleen bij activiteit sluiten, dus ik besloot om eenvoudigweg de kaart te verbergen / te tonen fragmenttransactie / verbergen


Antwoord 11

Ik respecteer alle antwoorden, maar ik vond deze one-liner-oplossing:
Als n het aantal tabbladen is, dan:

mViewPager.setOffscreenPageLimit(n);

Voorbeeld:
Indien vermeld :

mViewPager.setOffscreenPageLimit(2);

View pager implementeert een wachtrij, dus u hoeft het dat fragment niet te laten verwijderen. onCreateView wordt maar één keer aangeroepen.


Antwoord 12

Ik ben een beetje laat op het feest, maar geen van deze antwoorden heeft me geholpen in mijn geval. Ik gebruikte Google map als SupportMapFragmenten PlaceAutocompleteFragmentbeide in mijn fragment. Zoals alle antwoorden wezen op het feit dat het probleem zit in het feit dat SupportMapFragment de kaart is die opnieuw moet worden gemaakt en opnieuw moet worden getekend. Maar na het graven ontdekte ik dat mijn probleem eigenlijk lag bij PlaceAutocompleteFragment

Dus hier is de werkende oplossing voor degenen die met dit probleem worden geconfronteerd vanwege SupportMapFragmenten SupportMapFragment

//Global SupportMapFragment mapFragment;
 mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapFragment);
    FragmentManager fm = getChildFragmentManager();
    if (mapFragment == null) {
        mapFragment = SupportMapFragment.newInstance();
        fm.beginTransaction().replace(R.id.mapFragment, mapFragment).commit();
        fm.executePendingTransactions();
    }
    mapFragment.getMapAsync(this);
    //Global PlaceAutocompleteFragment autocompleteFragment;
    if (autocompleteFragment == null) {
        autocompleteFragment = (PlaceAutocompleteFragment) getActivity().getFragmentManager().findFragmentById(R.id.place_autoCompleteFragment);
    }

En in onDestroyView wis het SupportMapFragment en SupportMapFragment

@Override
public void onDestroyView() {
    super.onDestroyView();
    if (getActivity() != null) {
        Log.e("res","place dlted");
        android.app.FragmentManager fragmentManager = getActivity().getFragmentManager();
        android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.remove(autocompleteFragment);
        fragmentTransaction.commit(); 
       //Use commitAllowingStateLoss() if getting exception 
        autocompleteFragment = null;
    }
}

Antwoord 13

Geneste fragmenten worden momenteel niet ondersteund.
Probeer Ondersteuningspakket, revisie 11.


Antwoord 14

Heb je geprobeerd te verwijzen naar je aangepaste MapFragment-klasse in het lay-outbestand?

<?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="vertical" >
    <fragment
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapFragment"
        android:name="com.nfc.demo.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Antwoord 15

Als u alleen het antwoord van Vidar Wahlberg gebruikt, krijgt u een foutmelding wanneer u een andere activiteit opent (bijvoorbeeld) en teruggaat naar de kaart. Of in mijn geval een andere activiteit openen en vervolgens vanuit een nieuwe activiteit de kaart opnieuw openen (zonder de terugknop te gebruiken).
Maar als je de Vidar Wahlberg-oplossing en de Matt-oplossing combineert, heb je geen uitzonderingen.

indeling

<com.example.ui.layout.MapWrapperLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/map_relative_layout">
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/root">
        <fragment xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/map"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            class="com.google.android.gms.maps.SupportMapFragment" />
    </RelativeLayout>
</<com.example.ui.layout.MapWrapperLayout>

Fragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    setHasOptionsMenu(true);
    if (view != null) {
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent != null){
            parent.removeView(view);
        }
    }
    try {
        view = inflater.inflate(R.layout.map_view, null);
        if(view!=null){
            ViewGroup root = (ViewGroup) view.findViewById(R.id.root);
...
@Override
public void onDestroyView() {
    super.onDestroyView();
    Fragment fragment = this.getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.map);
    if (fragment != null)
        getFragmentManager().beginTransaction().remove(fragment).commit();
}

Antwoord 16

Ik had dit in viewPager en de crash was omdat elk fragment zijn eigen tag moest hebben, dubbele tags of id’s voor hetzelfde fragment zijn niet toegestaan.


Antwoord 17

Ik denk dat er een aantal bugs waren in de vorige App-Compat lib voor kind Fragment. Ik heb @Vidar Wahlberg en @Matt’s geprobeerd en ze werkten niet voor mij. Na het updaten van de appcompat-bibliotheek werkt mijn code perfect zonder extra inspanning.


Antwoord 18

Hier moet u rekening mee houden dat uw app in een van de twee gevallen ernstig zal crashen:-

1) Om fragment opnieuw met Maps te gebruiken, moet MapView Fragment worden verwijderd wanneer:
uw fragment met kaarten is vervangen door een ander fragment in onDestroyView-callback.

anders wanneer u hetzelfde fragment twee keer probeert op te blazen Dubbele ID, tag null of ouder-ID met een ander fragment voor com.google.android.gms.maps.MapFragment, treedt er een fout op.

2) Ten tweede mag u app.Fragment-bewerkingen niet combineren met
android.support.v4.app.Fragment API-bewerkingen bijv.niet gebruiken
android.app.FragmentTransaction om v4.app.Fragment type te verwijderen
MapView-fragment. Dit mengen zal opnieuw resulteren in een crash vanaf de fragmentzijde.

Hier is een voorbeeldcodefragment voor correct gebruik van MapView

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.serveroverload.yago.R;
/**
 * @author 663918
 *
 */
public class HomeFragment extends Fragment implements LocationListener {
    // Class to do operations on the Map
    GoogleMap googleMap;
    private LocationManager locationManager;
    public static Fragment newInstance() {
        return new HomeFragment();
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.home_fragment, container, false);
        Bundle bdl = getArguments();
        // setuping locatiomanager to perfrom location related operations
        locationManager = (LocationManager) getActivity().getSystemService(
                Context.LOCATION_SERVICE);
        // Requesting locationmanager for location updates
        locationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER, 1, 1, this);
        // To get map from MapFragment from layout
        googleMap = ((MapFragment) getActivity().getFragmentManager()
                .findFragmentById(R.id.map)).getMap();
        // To change the map type to Satellite
        // googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        // To show our current location in the map with dot
        // googleMap.setMyLocationEnabled(true);
        // To listen action whenever we click on the map
        googleMap.setOnMapClickListener(new OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                /*
                 * LatLng:Class will give us selected position lattigude and
                 * longitude values
                 */
                Toast.makeText(getActivity(), latLng.toString(),
                        Toast.LENGTH_LONG).show();
            }
        });
        changeMapMode(2);
        // googleMap.setSatellite(true);
        googleMap.setTrafficEnabled(true);
        googleMap.setBuildingsEnabled(true);
        googleMap.setMyLocationEnabled(true);
        return v;
    }
    private void doZoom() {
        if (googleMap != null) {
            googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(18.520430, 73.856744), 17));
        }
    }
    private void changeMapMode(int mapMode) {
        if (googleMap != null) {
            switch (mapMode) {
            case 0:
                googleMap.setMapType(GoogleMap.MAP_TYPE_NONE);
                break;
            case 1:
                googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                break;
            case 2:
                googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
                break;
            case 3:
                googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
                break;
            case 4:
                googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                break;
            default:
                break;
            }
        }
    }
    private void createMarker(double latitude, double longitude) {
        // double latitude = 17.385044;
        // double longitude = 78.486671;
        // lets place some 10 random markers
        for (int i = 0; i < 10; i++) {
            // random latitude and logitude
            double[] randomLocation = createRandLocation(latitude, longitude);
            // Adding a marker
            MarkerOptions marker = new MarkerOptions().position(
                    new LatLng(randomLocation[0], randomLocation[1])).title(
                    "Hello Maps " + i);
            Log.e("Random", "> " + randomLocation[0] + ", " + randomLocation[1]);
            // changing marker color
            if (i == 0)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
            if (i == 1)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
            if (i == 2)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_CYAN));
            if (i == 3)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
            if (i == 4)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
            if (i == 5)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
            if (i == 6)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_RED));
            if (i == 7)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_ROSE));
            if (i == 8)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_VIOLET));
            if (i == 9)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
            googleMap.addMarker(marker);
            // Move the camera to last position with a zoom level
            if (i == 9) {
                CameraPosition cameraPosition = new CameraPosition.Builder()
                        .target(new LatLng(randomLocation[0], randomLocation[1]))
                        .zoom(15).build();
                googleMap.animateCamera(CameraUpdateFactory
                        .newCameraPosition(cameraPosition));
            }
        }
    }
    /*
     * creating random postion around a location for testing purpose only
     */
    private double[] createRandLocation(double latitude, double longitude) {
        return new double[] { latitude + ((Math.random() - 0.5) / 500),
                longitude + ((Math.random() - 0.5) / 500),
                150 + ((Math.random() - 0.5) * 10) };
    }
    @Override
    public void onLocationChanged(Location location) {
        if (null != googleMap) {
            // To get lattitude value from location object
            double latti = location.getLatitude();
            // To get longitude value from location object
            double longi = location.getLongitude();
            // To hold lattitude and longitude values
            LatLng position = new LatLng(latti, longi);
            createMarker(latti, longi);
            // Creating object to pass our current location to the map
            MarkerOptions markerOptions = new MarkerOptions();
            // To store current location in the markeroptions object
            markerOptions.position(position);
            // Zooming to our current location with zoom level 17.0f
            googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position,
                    17f));
            // adding markeroptions class object to the map to show our current
            // location in the map with help of default marker
            googleMap.addMarker(markerOptions);
        }
    }
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub
    }
    @Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub
    }
    @Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub
    }
    @Override
    public void onDestroyView() {
        // TODO Auto-generated method stub
        super.onDestroyView();
        locationManager.removeUpdates(this);
        android.app.Fragment fragment = getActivity().getFragmentManager()
                .findFragmentById(R.id.map);
        if (null != fragment) {
            android.app.FragmentTransaction ft = getActivity()
                    .getFragmentManager().beginTransaction();
            ft.remove(fragment);
            ft.commit();
        }
    }
}

xml

<fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
       />

Het resultaat ziet er als volgt uit:-

Ik hoop dat het Iemand zal helpen.


Antwoord 19

In deze oplossing hoeft u geen statische variabele te nemen;

Button nextBtn;
private SupportMapFragment mMapFragment;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    if (mRootView != null) {
        ViewGroup parent = (ViewGroup) mRootView.getParent();
        Utility.log(0,"removeView","mRootView not NULL");
        if (parent != null) {
            Utility.log(0, "removeView", "view removeViewed");
            parent.removeAllViews();
        }
    }
    else {
        try {
            mRootView = inflater.inflate(R.layout.dummy_fragment_layout_one, container, false);//
        } catch (InflateException e) {
    /* map is already there, just return view as it is  */
            e.printStackTrace();
        }
    }
    return  mRootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    FragmentManager fm = getChildFragmentManager();
    SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.mapView);
    if (mapFragment == null) {
        mapFragment = new SupportMapFragment();
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(R.id.mapView, mapFragment, "mapFragment");
        ft.commit();
        fm.executePendingTransactions();
    }
    //mapFragment.getMapAsync(this);
    nextBtn = (Button) view.findViewById(R.id.nextBtn);
    nextBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Utility.replaceSupportFragment(getActivity(),R.id.dummyFragment,dummyFragment_2.class.getSimpleName(),null,new dummyFragment_2());
        }
    });
}`

Antwoord 20

Probeer een id (android:id=”@+id/maps_dialog”) in te stellen voor uw bovenliggende mapView-lay-out. Werkt voor mij.


Antwoord 21

Iedereen die hier nu komt en dit type fout krijgt bij het openen van een Dialogof ander Fragmentmet het Google Places AutocompleteSupportFragment, probeer deze eens -liner (ik weet niet hoe veilig dit is, maar het werkt voor mij):

autocompleteFragment.getFragmentManager().beginTransaction().remove(autocompleteFragment).commit();

voordat je je fragment verwijdert/vernietigt.


Antwoord 22

<?xml version="1.0" encoding="utf-8"?>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
   android:layout_height="match_parent" >
<com.google.android.gms.maps.MapView
    android:id="@+id/mapview"
    android:layout_width="100dip"
    android:layout_height="100dip"
    android:layout_alignParentTop="true"
    android:layout_alignRight="@+id/textView1"
    android:layout_marginRight="15dp" >
</com.google.android.gms.maps.MapView>

Waarom voegt u geen kaart in met behulp van het MapView-object in plaats van MapFragment ? Ik weet niet zeker of er een beperking is in MapView, hoewel ik het nuttig vond.

Other episodes