Doppelte ID, Tag null oder übergeordnete ID mit einem anderen Fragment für com.google.android.gms.maps.MapFragment

333

Ich habe eine Anwendung mit drei Registerkarten.

Jede Registerkarte verfügt über eine eigene XML-Layoutdatei. Die main.xml hat ein eigenes Kartenfragment. Es wird angezeigt, wenn die Anwendung zum ersten Mal gestartet wird.

Alles funktioniert gut, außer wenn ich zwischen Registerkarten wechsle. Wenn ich versuche, zur Registerkarte "Kartenfragment" zurückzukehren, wird dieser Fehler angezeigt. Das Wechseln zu und zwischen anderen Registerkarten funktioniert einwandfrei.

Was könnte hier falsch sein?

Dies ist meine Hauptklasse und meine main.xml sowie eine relevante Klasse, die ich verwende (das Fehlerprotokoll finden Sie auch unten).

Hauptklasse

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();
    }
}

Error

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
hermann
quelle
Versuchen Sie dies - geben Sie super.onCreateView zurück (inflater, container, savedInstanceState); anstelle von super.onCreateView (inflater, container, savedInstanceState); return inflater.inflate (R.layout.main, container, false);
Nik
Sie sollten Ihr Fragment nicht hinzufügen, wenn savedInstanceState nicht null ist.
Muyiou
Schauen Sie sich diesen Kommentar an. Es könnte Ihnen helfen: stackoverflow.com/questions/15562416/…
Oleksandr
2
Bitte ändern Sie die akzeptierte Antwort! Sie haben eine sehr schlechte Antwort ausgewählt, die zu Speicherlecks führt! Die richtige Antwort lautet: stackoverflow.com/a/19815266/902276
Daniele Segato

Antworten:

400

Die Antwort, die Matt vorschlägt, funktioniert, aber die Karte wird neu erstellt und neu gezeichnet, was nicht immer wünschenswert ist. Nach vielen Versuchen und Irrtümern fand ich eine Lösung, die für mich funktioniert:

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;
}

Hier ist "map.xml" (R.layout.map) mit 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>

Ich hoffe, das hilft, aber ich kann nicht garantieren, dass es keine nachteiligen Auswirkungen hat.

Bearbeiten: Es gab einige nachteilige Auswirkungen, z. B. beim Beenden und erneuten Starten der Anwendung. Da die Anwendung nicht unbedingt vollständig heruntergefahren wird (sondern nur im Hintergrund in den Ruhezustand versetzt wird), schlägt der zuvor eingereichte Code beim Neustart der Anwendung fehl. Ich habe den Code auf etwas aktualisiert, das für mich funktioniert, sowohl beim Ein- und Aussteigen aus der Karte als auch beim Beenden und Neustarten der Anwendung. Ich bin mit dem Try-Catch-Bit nicht allzu zufrieden, aber es scheint gut genug zu funktionieren. Beim Betrachten der Stapelverfolgung kam mir der Gedanke, dass ich nur überprüfen konnte, ob sich das Kartenfragment im FragmentManager befindet, ohne dass der Try-Catch-Block benötigt wurde und der Code aktualisiert wurde.

Weitere Änderungen: Es stellt sich heraus, dass Sie diesen Try-Catch doch brauchen. Nur nach dem Kartenfragment zu suchen, stellte sich schließlich als nicht so gut heraus. Blergh.

Vidar Wahlberg
quelle
25
Dies ist eine falsche Antwort -1! Sie verlieren eine Aktivität mit dem statischen Modifikator für eine Ansicht. Die Hauptursache für dieses Problem ist wahrscheinlich eine weitere durchgesickerte Aktivität, die nicht durch Müll gesammelt werden kann, da Sie einen starken Verweis darauf haben. Falls eine InflateException ausgelöst wird, verwenden Sie eine Ansicht mit dem Kontext einer zerstörten Aktivität! Finden Sie besser andere Speicherlecks in Ihrer App, dies wird alle Probleme lösen.
Tomrozb
1
Ich denke, wir können WeakReference verwenden, um Speicherverluste zu vermeiden.
Desmond Lua
2
Das funktioniert auch bei mir +1. Sie sind nicht verpflichtet, statische Referenz der Ansicht zu verwenden
Karol Żygłowicz
4
Tu das nicht !!! Dies führt zu einem Speicherverlust. Der einzige Grund dafür ist, dass Sie ein Fragment aus XML in ein anderes Fragment aufblasen. Das sollst du NICHT tun! Sie sollten den ChildFragmentManager verwenden und das Fragment in onViewCreated () hinzufügen!
Daniele Segato
1
Ja, dies wird in der Tat die Aktivität auslaufen lassen. Eine funktionierende Lösung wurde in stackoverflow.com/a/27592123/683763 gefunden . Die Idee ist, die SupportMapFragmentin- onDestroyViewMethode manuell zu entfernen .
ULazdins
277

Das Problem ist, dass das, was Sie versuchen, nicht getan werden sollte. Sie sollten keine Fragmente in anderen Fragmenten aufblasen. Aus der Android- Dokumentation :

Hinweis: Sie können ein Layout nicht in ein Fragment aufblasen, wenn dieses Layout ein <Fragment> enthält. Verschachtelte Fragmente werden nur unterstützt, wenn sie dynamisch zu einem Fragment hinzugefügt werden.

Obwohl Sie die Aufgabe möglicherweise mit den hier vorgestellten Hacks ausführen können, empfehle ich Ihnen dringend, dies nicht zu tun. Es ist unmöglich sicher zu sein, dass diese Hacks die Aufgaben jedes neuen Android-Betriebssystems erfüllen, wenn Sie versuchen, ein Layout für ein Fragment mit einem anderen Fragment aufzublasen.

Die einzige von Android unterstützte Möglichkeit, ein Fragment einem anderen Fragment hinzuzufügen, besteht in einer Transaktion des untergeordneten Fragmentmanagers.

Ändern Sie einfach Ihr XML-Layout in einen leeren Container (fügen Sie bei Bedarf eine ID hinzu):

<?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>

Dann in der 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);
}
Justin Breitfeller
quelle
4
Unter stackoverflow.com/questions/13733299/… finden Sie Beispiele zum programmgesteuerten Erstellen eines Kartenfragments und zum Initialisieren der Karte.
Kristopher Johnson
1
Siehe auch stackoverflow.com/questions/19239175/… für eine Problemumgehung für offensichtliche Fehler bei der Unterstützung von untergeordneten Fragmenten.
Kristopher Johnson
Ich bin auf dieses Problem gestoßen, 4.3als ich ein SupportMapFragmentin XML definiertes verwendet habe. Das Problem wurde behoben, indem das Fragment dynamisch erstellt und in eine Containeransicht eingefügt wurde. Siehe diese SO-Antwort .
Theblang
Sehr nützliche Antwort. Wie können wir einen Rückruf zur Hauptfunktion von onCreate () durchführen?
Utopia
2
Verwenden Sie laut doc SupportMapFragment.newInstance(); developer.google.com/maps/documentation/android-api/map
Jemshit Iskenderov
178

Ich hatte das gleiche Problem und konnte es beheben, indem ich das MapFragmentin der onDestroy()Methode der FragmentKlasse manuell entfernte . Hier ist Code, der funktioniert und auf die MapFragmentBy-ID im XML verweist :

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

Wenn Sie das nicht MapFragmentmanuell entfernen , bleibt es hängen, sodass das erneute Erstellen / Anzeigen der Kartenansicht nicht viele Ressourcen kostet. Es scheint, dass das Beibehalten des Basiswerts MapViewfür das Hin- und Herwechseln zwischen Registerkarten ideal ist. Bei Verwendung in Fragmenten führt dieses Verhalten jedoch dazu MapView, dass bei jedem neuen MapFragmentmit derselben ID ein Duplikat erstellt wird . Die Lösung besteht darin, das manuell zu entfernenMapFragment , die zugrunde liegende Karte bei jedem Aufblasen des Fragments und somit neu zu erstellen.

Ich habe dies auch in einer anderen Antwort vermerkt [ 1 ].

Matt
quelle
Die App stürzt ab, wenn Sie auf die Home-Schaltfläche des Geräts klicken. In den Entwickleroptionen wird "Aktivitäten nicht beibehalten" angezeigt.
jul
23
Dies funktioniert, aber wenn ich meinen Bildschirm drehe, stürzt meine App mit der folgenden Ausnahme ab: Auslöser: java.lang.IllegalStateException: Kann diese Aktion nach onSaveInstanceState
jramoyo
1
Für diejenigen, die interessiert sein könnten, können Sie die durch Bildschirmdrehung verursachte Ausnahme beseitigen, indem Sie die ursprüngliche Ausrichtung im Konstruktor des Fragments speichern und die obige Transaktion nur aufrufen, wenn die Ausrichtung NICHT geändert wurde. Wenn es geändert wurde, müssen Sie nicht mit doppelten IDs kämpfen, da es nicht vorhanden ist, wenn die Ansicht nach der Drehung neu erstellt wird. Ich kann die Antwort bearbeiten und ein Code-Snippet bereitstellen, wenn es Matt nichts ausmacht.
Stan
1
Hmm für mich wird das Kartenfragment nicht entfernt. Ich muss etwas falsch machen, aber wenn ich getActivity (). GetSupportFragmentManager (). GetFragments () aufrufe, bleibt das Fragment nach dem Aufruf von remove (f) .commit. Hat jemand eine Idee warum? (Ich habe getFragManager durch getSupportFragManager ersetzt)
Daniel Wilson
10
commitAllowingStateLoss vermeidet die IllegalStateException-Ausnahme.
Héctor Júdez Sapena
22

Das ist meine Antwort:

1, Erstellen Sie eine Layout-XML wie folgt:

<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 Fügen Sie in der Fragment-Klasse programmgesteuert eine Google Map hinzu.

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();
    }
} 
Zou
quelle
2
mMapFragment.getMap();kehrt zurück null. Irgendeine Idee warum?
Anas Azeem
@AnasAzeem, das programmgesteuerte Erstellen eines Fragments löst das Problem genau. In Ihrem Fall müssen Sie möglicherweise keine mMap für die Lösung abrufen.
yesildal
@AnasAzeem Sie sollten get getMapAsync verwenden, das nach der Initialisierung (im Hintergrund) eine Karteninstanz korrekt zurückgibt. Dies ist die "richtige" Art, mit Google Maps zu arbeiten und hat nichts mit Fragmenten zu tun
Ganesh Krishnan
10
  1. Wie von @Justin Breitfeller erwähnt, ist die @ Vidar Wahlberg-Lösung ein Hack, der in zukünftigen Android-Versionen möglicherweise nicht funktioniert.
  2. @Vidar Wahlberg führt einen Hack durch, weil eine andere Lösung "dazu führen kann, dass die Karte neu erstellt und neu gezeichnet wird, was nicht immer wünschenswert ist". Das Neuzeichnen von Karten könnte verhindert werden, indem das alte Kartenfragment beibehalten wird, anstatt jedes Mal eine neue Instanz zu erstellen.
  3. @ Matt-Lösung funktioniert bei mir nicht (IllegalStateException)
  4. Wie von @Justin Breitfeller zitiert: "Sie können ein Layout nicht in ein Fragment aufblasen, wenn dieses Layout a enthält. Verschachtelte Fragmente werden nur unterstützt, wenn sie dynamisch zu einem Fragment hinzugefügt werden."

Meine Lösung:

@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;
}
Desmond Lua
quelle
2
Danke @Desmond Ihre Lösung hat bei mir einwandfrei funktioniert. Das einzige, woran Sie sich erinnern müssen, ist, die Karte NICHT im Layout zu erstellen. Die Kartenerstellung in dieser Lösung ist in den Code eingebettet. Ändern Sie daher <fragment android: name = "com.google.android.gms.maps.SupportMapFragment"> in z. B. <LinearLayout id = "@ + id / map />
kosiara - Bartosz Kosarzycki
7

Deklarieren Sie das SupportMapFragment-Objekt global

    private SupportMapFragment mapFragment;

In der onCreateView () -Methode wird der folgende Code eingefügt

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

Geben Sie in onDestroyView () den folgenden Code ein

@Override
public void onDestroyView() {
   super.onDestroyView();

    if (mapFragment != null)
        getFragmentManager().beginTransaction().remove(mapFragment).commit();
}

Geben Sie in Ihrer XML-Datei den folgenden Code ein

 <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"
    />

Der obige Code hat mein Problem gelöst und funktioniert einwandfrei

Digvijay Machale
quelle
3

Ich würde replace()eher empfehlen als attach()/ detach()in Ihrer Tab-Behandlung.

Oder wechseln Sie zu ViewPager. Hier ist ein Beispielprojekt, das ViewPagermit Registerkarten 10 Karten hostet.

CommonsWare
quelle
Aber ersetzen Sie geben outofmemry Fehler als was tun sollte, wenn wir Fenster trennen verwenden, als Map-Problem auftreten.
Vishal Android-Entwickler
3

Eine andere Lösung:

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

Das ist es, wenn nicht null, müssen Sie es nicht neu initialisieren. Das Entfernen vom übergeordneten Element ist ein unnötiger Schritt.

AnonymousDev
quelle
Dies ist die beste Lösung für meinen Fall. Ich habe diesen Fehler erhalten, weil ich zwei Fragmente für mein Navigationsdiagramm verwendet habe, und dies hat mein Problem behoben.
Kennedy Kambo
Dies ist die beste Lösung für meinen Fall. Ich habe diesen Fehler erhalten, weil ich zwei Fragmente für mein Navigationsdiagramm verwendet habe, und dies hat mein Problem behoben.
Kennedy Kambo
2

Ich habe heute Stunden verloren, um den Grund zu finden. Glücklicherweise liegt dieses Problem nicht an der Implementierung von MapFragment. Leider funktioniert dies nicht, da verschachtelte Fragmente nur über die Support-Bibliothek ab Version 11 unterstützt werden.

Meine Implementierung hat eine Aktivität mit Aktionsleiste (im Registerkartenmodus) mit zwei Registerkarten (kein Viewpager), von denen eine die Karte und die andere eine Liste von Einträgen enthält. Natürlich war ich ziemlich naiv, MapFragment in meinen Tab-Fragmenten zu verwenden, und voila, die App stürzte jedes Mal ab, wenn ich zurück zu Map-Tab wechselte.

(Das gleiche Problem hätte ich auch für den Fall, dass mein Tab-Fragment ein Layout mit einem anderen Fragment aufblasen würde).

Eine Möglichkeit besteht darin, MapView (anstelle von MapFragment) mit etwas Aufwand zu verwenden (siehe MapView- Dokumente) als Drop-In-Ersatz in der layout.xml). Eine andere Möglichkeit besteht darin, die Support-Bibliothek ab Version 11 zu verwenden und dann programmatisch vorzugehen Da verschachtelte Fragmente weder über das Layout unterstützt werden, noch einfach programmgesteuert umgangen werden, indem das Fragment explizit zerstört wird (wie in der Antwort von Matt / Vidar), wird übrigens der gleiche Effekt mit MapView erzielt (Option 1).

Aber eigentlich wollte ich die Karte nicht jedes Mal verlieren, wenn ich sie abblätterte, das heißt, ich wollte sie nur nach Abschluss der Aktivität im Speicher behalten und bereinigen. Deshalb habe ich beschlossen, die Karte während des Tabulierens einfach auszublenden / anzuzeigen, siehe FragmentTransaction / hide

Hol dir welche
quelle
2

Für diejenigen, die immer noch auf dieses Problem stoßen, besteht der beste Weg, um sicherzustellen, dass dieser Fehler bei einer Karte in einem Tab nicht auftritt, darin, das Fragment zu erweitern, SupportMapFragmentanstatt ein SupportMapFragmentin das für den Tab verwendetes Fragment zu verschachteln .

Ich habe das gerade mit a ViewPagermit a funktioniert FragmentPagerAdapter, mit dem SupportMapFragment auf der dritten Registerkarte.

Hier ist die allgemeine Struktur. Beachten Sie, dass die onCreateView()Methode nicht überschrieben werden muss und keine Layout-XML-Datei aufgeblasen werden muss:

public class MapTabFragment extends SupportMapFragment 
                                    implements OnMapReadyCallback {

    private GoogleMap mMap;
    private Marker marker;


    public MapTabFragment() {
    }

    @Override
    public void onResume() {
        super.onResume();

        setUpMapIfNeeded();
    }

    private void setUpMapIfNeeded() {

        if (mMap == null) {

            getMapAsync(this);
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

        mMap = googleMap;
        setUpMap();
    }

    private void setUpMap() {

        mMap.setMyLocationEnabled(true);
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        mMap.getUiSettings().setMapToolbarEnabled(false);


        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

            @Override
            public void onMapClick(LatLng point) {

                //remove previously placed Marker
                if (marker != null) {
                    marker.remove();
                }

                //place marker where user just clicked
                marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker")
                        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));

            }
        });

    }


}

Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Hier ist der vollständige Klassencode, mit dem ich getestet habe, einschließlich des Platzhalterfragments für die ersten beiden Registerkarten und des Kartenfragments für die dritte Registerkarte:

public class MainActivity extends AppCompatActivity implements ActionBar.TabListener{


    SectionsPagerAdapter mSectionsPagerAdapter;

    ViewPager mViewPager;

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

        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
        }

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }


    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {

            switch (position) {
                case 0:
                    return PlaceholderFragment.newInstance(position + 1);
                case 1:
                    return PlaceholderFragment.newInstance(position + 1);
                case 2:
                    return MapTabFragment.newInstance(position + 1);
            }

            return null;
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return 3;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();

            switch (position) {
                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
            }
            return null;
        }
    }


    public static class PlaceholderFragment extends Fragment {

        private static final String ARG_SECTION_NUMBER = "section_number";

        TextView text;

        public static PlaceholderFragment newInstance(int sectionNumber) {
            PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            return fragment;
        }

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);

            text = (TextView) rootView.findViewById(R.id.section_label);
            text.setText("placeholder");

            return rootView;
        }
    }

    public static class MapTabFragment extends SupportMapFragment implements
            OnMapReadyCallback {

        private static final String ARG_SECTION_NUMBER = "section_number";

        private GoogleMap mMap;
        private Marker marker;


        public static MapTabFragment newInstance(int sectionNumber) {
            MapTabFragment fragment = new MapTabFragment();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            return fragment;
        }

        public MapTabFragment() {
        }

        @Override
        public void onResume() {
            super.onResume();

            Log.d("MyMap", "onResume");
            setUpMapIfNeeded();
        }

        private void setUpMapIfNeeded() {

            if (mMap == null) {

                Log.d("MyMap", "setUpMapIfNeeded");

                getMapAsync(this);
            }
        }

        @Override
        public void onMapReady(GoogleMap googleMap) {
            Log.d("MyMap", "onMapReady");
            mMap = googleMap;
            setUpMap();
        }

        private void setUpMap() {

            mMap.setMyLocationEnabled(true);
            mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
            mMap.getUiSettings().setMapToolbarEnabled(false);


            mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

                @Override
                public void onMapClick(LatLng point) {

                    Log.d("MyMap", "MapClick");

                    //remove previously placed Marker
                    if (marker != null) {
                        marker.remove();
                    }

                    //place marker where user just clicked
                    marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker")
                            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));

                    Log.d("MyMap", "MapClick After Add Marker");

                }
            });

        }
    }
}
Daniel Nugent
quelle
2

Ich respektiere alle Antworten, aber ich habe diese Einzeiler-Lösung gefunden: Wenn n die Anzahl der Registerkarten ist, dann:

 mViewPager.setOffscreenPageLimit(n);

Beispiel: Im genannten Fall:

 mViewPager.setOffscreenPageLimit(2);

View Pager implementiert eine Warteschlange, sodass Sie dieses Fragment nicht entfernen lassen müssen. onCreateView wird nur einmal aufgerufen.

Jayant Arora
quelle
1

Sie kehren zweimal zurück oder blasen das Layout auf. Überprüfen Sie nur, ob Sie nur einmal aufblasen.

Mahdi Giveie
quelle
0

Haben Sie versucht, Ihre benutzerdefinierte MapFragmentKlasse in der Layoutdatei zu referenzieren ?

<?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>
JJD
quelle
Könnten Sie bitte Code für benutzerdefinierte Karte Fragment com.nfc.demo.MapFragment
Mina Fawzy
Ich bin nicht der Autor des Codes - ich habe nur den fraglichen Code verwendet. Du musst hermann fragen.
JJD
0

Wenn Sie nur die Antwort von Vidar Wahlberg verwenden, wird eine Fehlermeldung angezeigt, wenn Sie eine andere Aktivität öffnen (z. B.) und zur Karte zurückkehren. Oder öffnen Sie in meinem Fall eine andere Aktivität und öffnen Sie dann von einer neuen Aktivität aus die Karte erneut (ohne die Schaltfläche "Zurück" zu verwenden). Wenn Sie jedoch die Vidar Wahlberg-Lösung und die Matt-Lösung kombinieren, gibt es keine Ausnahmen.

Layout

<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();
}
Vlad Hudnitsky
quelle
0

Ich hatte dies in viewPager und der Absturz war, weil jedes Fragment ein eigenes Tag haben musste, doppelte Tags oder IDs für dasselbe Fragment sind nicht erlaubt.

user1396018
quelle
0

Ich denke, es gab einige Fehler in der vorherigen App-Compat-Bibliothek für untergeordnetes Fragment. Ich habe @Vidar Wahlberg und @ Matt's ans ausprobiert und sie haben bei mir nicht funktioniert. Nach dem Aktualisieren der Appcompat-Bibliothek läuft mein Code ohne zusätzlichen Aufwand einwandfrei.

Papa d
quelle
0

Hier ist zu beachten, dass Ihre App in zwei Fällen schwer abstürzt: -

1) Um Fragmente wieder mit Maps wiederzuverwenden, muss MapView Fragment entfernt werden, wenn Ihr Fragment mit Maps im onDestroyView-Rückruf durch ein anderes Fragment ersetzt wurde.

Andernfalls tritt ein Fehler auf, wenn Sie versuchen, dasselbe Fragment zweimal aufzublasen. Eine doppelte ID, ein Tag null oder eine übergeordnete ID mit einem anderen Fragment für com.google.android.gms.maps.MapFragment tritt auf.

2) Zweitens dürfen Sie keine app.Fragment-Operationen mit android.support.v4.app.Fragment-API-Operationen mischen, z. B. verwenden Sie nicht android.app.FragmentTransaction, um das MapView-Fragment vom Typ v4.app.Fragment zu entfernen. Das Mischen führt erneut zu einem Absturz von der Fragmentseite.

Hier ist ein Beispielcode-Snippet für die korrekte Verwendung von 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"
       />

Ergebnis sieht so aus: -Geben Sie hier die Bildbeschreibung ein

Hoffe es wird jemandem helfen.

Hitesh Sahu
quelle
0

In dieser Lösung müssen Sie keine statische Variable verwenden.

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());
        }
    });

}`
Lalit Kumar
quelle
0

Ich bin etwas spät zur Party, aber keine dieser Antworten hat mir in meinem Fall geholfen. Ich habe Google Map als SupportMapFragment und PlaceAutocompleteFragment in meinem Fragment verwendet. Wie alle Antworten darauf hinwiesen, dass das Problem darin besteht, dass SupportMapFragment die Karte ist, die neu erstellt und neu gezeichnet werden soll. Nachdem ich jedoch herausgefunden hatte, dass mein Problem tatsächlich bei PlaceAutocompleteFragment lag

Hier ist die funktionierende Lösung für diejenigen, die aufgrund von SupportMapFragment und SupportMapFragment mit diesem Problem konfrontiert sind

 //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);

    }

Und in onDestroyView löschen Sie SupportMapFragment und 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;
    }


}
Ratul Bin Tazul
quelle
0

Versuchen Sie, eine ID (android: id = "@ + id / maps_dialog") für Ihr übergeordnetes mapView-Layout festzulegen. Funktioniert bei mir.

hieudev develo
quelle
0

Wenn Sie jetzt hierher kommen und diese Art von Fehler beim Öffnen des einen Dialogoder anderen Fragmentmit Google Places erhalten AutocompleteSupportFragment, versuchen Sie diesen Einzeiler (ich weiß nicht, wie sicher dies ist, aber es funktioniert für mich):

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

bevor Sie Ihr Fragment entlassen / zerstören.

barnacle.m
quelle
-1
<?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>

Warum fügen Sie keine Karte mit dem MapView-Objekt anstelle von MapFragment ein? Ich bin mir nicht sicher, ob es in MapView Einschränkungen gibt, obwohl ich es hilfreich fand.

Ankur Gautam
quelle
Entschuldigung, ich habe erfahren, dass dies die veraltete Vorgängerversion von Google Maps API ist
Ankur Gautam