web-dev-qa-db-fra.com

Comment savoir si la carte est prête à être utilisée lors de l'utilisation de SupportMapFragment?

Dans la méthode onCreate, je me sers de la SupportMapFragment pour afficher une carte.

    SupportMapFragment fragment = new SupportMapFragment();
    getSupportFragmentManager().beginTransaction()
            .add(Android.R.id.content, fragment).commit();

Parallèlement à cela, je voudrais ajouter un marqueur. Le problème est que lorsque l'appel à getMap est nul, quand puis-je réessayer? Puis-je m'inscrire à un événement ou est-ce que mon approche est fausse en soi?

    mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
    if(mMap == null)
        //what do I do here?

La carte est en fait affichée au téléphone, mais il semble que je n’aie aucune chance d’obtenir la référence pour ajouter des marqueurs.

METTRE À JOUR:

La raison pour laquelle j'ai créé SupportMapFragment via le constructeur est parce que la setContentView typique se bloquait et ne fonctionnait pas. Cela m'a mis dans la situation difficile où je ne pouvais pas obtenir ma référence dans la méthode onCreate puisque je créais en fait la SupportMapFragment à cette époque. Après une enquête plus approfondie, il semble que mon problème setContentView était un sous-produit de ne pas avoir à la fois le fichier jar de Google-play-services ET le module/src configuré dans le cadre du projet global. En effectuant ces deux tâches, setContentView fonctionne maintenant et je peux obtenir la référence via getMap() comme je l’attendais.

lots.xml ...

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

LotsActivity.Java ...

public class LotsActivity extends FragmentActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.lots);

        GoogleMap mMap;
        mMap = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
        if(mMap == null)
            //this should not occur now
    }
29
Aaron McIver

EDIT: getMap est obsolète maintenant

Le problème est que lorsque l'appel à getMap est nul, quand puis-je réessayer?

Cela dépend de la nature du problème.

Si vous configurez la SupportMapFragment via l'élément <fragment> dans la présentation, vous pouvez appeler getMap() avec succès dans onCreate(). Mais, si vous créez la SupportMapFragment via le constructeur, c'est trop tôt, la GoogleMap n'existe pas encore. Vous pouvez étendre SupportMapFragment et remplacer onActivityCreated(), car getMap() est prêt d'ici là.

Cependant, getMap() peut aussi renvoyer null pour un problème plus grave, tel que les services Google Play n'étant pas installés. Vous devez utiliser quelque chose comme GooglePlayServicesUtil.isGooglePlayServicesAvailable() pour détecter cette condition et la traiter comme vous le souhaitez.

35
CommonsWare

J'ai fini par étendre la classe SupportMapFragment et utiliser un rappel. Le code est ici:

public class MySupportMapFragment extends SupportMapFragment {

public MapViewCreatedListener itsMapViewCreatedListener;

// Callback for results

public abstract static class MapViewCreatedListener {
    public abstract void onMapCreated();
}

@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = super.onCreateView(inflater, container, savedInstanceState);
    // Notify the view has been created
    if( itsMapViewCreatedListener != null ) {
        itsMapViewCreatedListener.onMapCreated();
    }
    return view;
}
}

J'aurais préféré utiliser une interface et remplacer la méthode onAttach (activité), mais dans mon cas, je ne voulais pas que le rappel retourne à ma MainActivity. Je voulais que cela revienne à une instance de Fragment. (GoogleMap était essentiellement un fragment à l'intérieur d'un fragment) J'ai configuré le rappel et chargé par programme la carte avec cela. Je voudrais avoir mis itsMapViewCreatedListener dans le constructeur de MySupportMapFragment, mais l'utilisation de constructeurs autres que des constructeurs sans paramètre est déconseillée.

itsMySupportMapFragment = new MySupportMapFragment();
MapViewCreatedListener mapViewCreatedListener = new MapViewCreatedListener() {
    @Override
    public void onMapCreated() {
        initPlacesGoogleMapCtrl();
    }
};
itsMySupportMapFragment.itsMapViewCreatedListener = mapViewCreatedListener;
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.mapFragmentContainer, itsMySupportMapFragment);
transaction.addToBackStack(null);
transaction.commit();

Et puis, quand on m'a rappelé, je pouvais avoir la carte. plus nul!

public void initPlacesGoogleMapCtrl() {
    // Map ready, get it.
    GoogleMap googleMap = itsMySupportMapFragment.getMap();
    // Do what you want...
}
14
strangeluck

Je voudrais commenter la réponse de CommonsWare mais je n'ai pas assez de représentant pour cela. Quoi qu'il en soit, je rencontrais également le problème suivant: getMap () renverrait null dans onActivityCreated. Ma configuration est la suivante: j'ai MainActivity qui contient un fragment. Dans la méthode onCreateView de ce fragment, j'ai créé SupportMapFragment, puis je l'ai ajouté au fragment via childFragmentManager. Je gardais une référence à SupportMapFragment et m'attendais à ce qu'elle me donne la carte dans onActivityCreated, ce qu'elle ne faisait pas. La solution à ce problème consistait à remplacer le onActivityCreated du SupportMapFragment mais pas le fragment parent. Je l'ai fait comme ça dans onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_location, container, false);
    mMapFragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mMap = mMapFragment.getMap();
            if (mMap != null) {
                setupMap();
            }
        }
    };
    getChildFragmentManager().beginTransaction().add(R.id.framelayout_location_container, mMapFragment).commit();
return v;   
}
11
hordurh

Le mois dernier (décembre 2014), Google a donné la solution officielle à ce problème. Dans le plus récent (6.5) Services Google Play :

La méthode getMap () dans MapView et MapFragment est maintenant déconseillée au profit de la nouvelle méthode getMapAsync ().

Avec getMapAsync(OnMapReadyCallback callback) , vous pouvez configurer un programme d'écoute lorsque GoogleMap est prêt. Il est passé en rappel et il est fourni non nul.

Google a fourni exemple de code pour cela:

public class MainActivity extends FragmentActivity
    implements OnMapReadyCallback {
...
}

et lors de l'initialisation de fragment:

MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

quand la carte est prête, votre rappel sera appelé

@Override
public void onMapReady(GoogleMap map) {
    map.addMarker(new MarkerOptions()
        .position(new LatLng(0, 0))
        .title("Marker"));
}
7
michalbrz

Avec les derniers services Google, vous pouvez utiliser MapFragment.getMapAsync . Directement à partir de la documentation.

Définit un objet de rappel qui sera déclenché lorsque l'instance de GoogleMap est prête à être utilisée.

0
Mojo Risin

si map == null alors trouver la carte

 if (mGoogleMap == null)
    {
        SupportMapFragment mapFragment1 = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        mapFragment1.getMapAsync(this);
    }

puis appelez votre fonction onMapReady ();

0
Mahesh Gawhane

Vous pouvez également utiliser MapsInitializer.initialize(context); si le problème est lié aux bibliothèques non initialisées.

0
theelfismike