web-dev-qa-db-fra.com

MapView dans un fragment (nid d'abeille)

maintenant que le SDK final est sorti avec google apis - quelle est la meilleure façon de créer un fragment avec MapView? MapView a besoin d'une MapActivity pour fonctionner correctement.

Faire en sorte que l'activité gérant les fragments hérite de MapActivity (mauvaise solution car cela va à l'encontre de l'idée que les fragments sont autonomes) et utiliser une mise en page standard basée sur XML ne fonctionne pas. J'obtiens une NullPointerException dans MapActivity.setupMapView ():

 E/AndroidRuntime (597): causée par: Java.lang.NullPointerException 
 E/AndroidRuntime (597): à com.google.Android.maps.MapActivity.setupMapView (MapActivity.Java:400 ) 
 E/AndroidRuntime (597): sur com.google.Android.maps.MapView. (MapView.Java:289) 
 E/AndroidRuntime (597): sur com.google.Android. maps.MapView. (MapView.Java:264) 
 E/AndroidRuntime (597): sur com.google.Android.maps.MapView. (MapView.Java:247) 

Ma deuxième idée était de créer le MapView par programme et de transmettre l'activité associée (via getActivity ()) en tant que contexte au constructeur MapView. Ne marche pas:

 E/AndroidRuntime (834): causée par: Java.lang.IllegalArgumentException: MapViews ne peut être créé qu'à l'intérieur d'instances de MapActivity. 
 E/AndroidRuntime (834): sur com.google.Android. maps.MapView. (MapView.Java:291) 
 E/AndroidRuntime (834): sur com.google.Android.maps.MapView. (MapView.Java:235) 
 E/AndroidRuntime ( 834): sur de.foo.FinderMapFragment.onCreateView (FinderMapFragment.Java:225) 
 E/AndroidRuntime (834): sur Android.app.FragmentManagerImpl.moveToState (FragmentManager.Java:708) 
 E/AndroidRuntime (834): sur Android.app.FragmentManagerImpl.moveToState (FragmentManager.Java:900) 
 E/AndroidRuntime (834): sur Android.app.FragmentManagerImpl.addFragment (FragmentManager.Java:978) 
 E/AndroidRuntime (834): sur Android.app.Activity.onCreateView (Activity.Java:4090) 
 E/AndroidRuntime (834): sur Android.view.LayoutInflater.createViewFromTag (LayoutInflater.Java : 664) 

Vraiment, il devrait y avoir quelque chose comme MapFragment qui s'occupe des threads d'arrière-plan dont MapView a besoin, je suppose ... Alors, quelle est la meilleure pratique actuelle pour le faire?

Merci et salutations de l'Allemagne, Valentin

81
Valentin

Depuis le 03.12.2012, Google a publié Google Maps Android API v2 . Vous pouvez maintenant oublier ces problèmes. - https://developers.google.com/maps/documentation/Android/

Exemple utilisant une nouvelle API - https://developers.google.com/maps/documentation/Android/start#add_a_map

Cette API fonctionnera pendant au moins Android API 8, alors utilisez-la;).

Alors maintenant, vous pouvez simplement utiliser la classe de fragments "com.google.Android.gms.maps.MapFragment". Il affichera la carte dans votre activité. Exemple de mise en page du lien ci-dessus:

<?xml version="1.0" encoding="utf-8"?>
<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.MapFragment"/>
8
Paul Annekov

J'ai réussi à résoudre ce problème en utilisant TabHost en fragment.

Voici l'idée (brièvement):

  1. MainFragmentActivity étend FragmentActivity (depuis la bibliothèque de support) et a MapFragment.

  2. MyMapActivity étend MapActivity et contient MapView .

  3. LocalActivityManagerFragment hôtes LocalActivityManager

  4. MapFragment étend LocalActivityManagerFragment.

  5. Et LocalActivityManager contient une activité MyMapActivity.

Exemple d'implémentation: https://github.com/inazaruk/map-fragment .


enter image description here

87
inazaruk

Comme indiqué sur Google Groups , Peter Doyle a également créé une bibliothèque de compatibilité personnalisée prenant en charge Google Maps. Android-support-v4-googlemaps

Cependant, il y a aussi un inconvénient:

Actuellement, un inconvénient est que TOUTES les classes étendant FragmentActivity sont MapActivitys. Il est possible de créer une classe distincte (c'est-à-dire FragmentMapActivity), mais cela nécessite une refactorisation du code FragmentActivity.

23
TomTasche

Juste pour clarifier la réponse. J'ai essayé l'approche suggérée par inazaruk et ChristophK. En fait, vous pouvez exécuter n'importe quelle activité dans un fragment - pas seulement Google Maps. Voici le code qui implémente l'activité google map en tant que fragment grâce à inazaruk et ChristophK.

import com.actionbarsherlock.app.SherlockFragment;
import Android.view.Window;

import Android.app.LocalActivityManager;
import Android.content.Intent;
import Android.os.Bundle;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;

public class MapFragment extends SherlockFragment {
    private static final String KEY_STATE_BUNDLE = "localActivityManagerState";

    private LocalActivityManager mLocalActivityManager;

    protected LocalActivityManager getLocalActivityManager() {
        return mLocalActivityManager;
    }

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

        Bundle state = null;
        if (savedInstanceState != null) {
            state = savedInstanceState.getBundle(KEY_STATE_BUNDLE);
        }

        mLocalActivityManager = new LocalActivityManager(getActivity(), true);
        mLocalActivityManager.dispatchCreate(state);
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            //This is where you specify you activity class
        Intent i = new Intent(getActivity(), GMapActivity.class); 
        Window w = mLocalActivityManager.startActivity("tag", i); 
        View currentView=w.getDecorView(); 
        currentView.setVisibility(View.VISIBLE); 
        currentView.setFocusableInTouchMode(true); 
        ((ViewGroup) currentView).setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        return currentView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBundle(KEY_STATE_BUNDLE,
                mLocalActivityManager.saveInstanceState());
    }

    @Override
    public void onResume() {
        super.onResume();
        mLocalActivityManager.dispatchResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mLocalActivityManager.dispatchPause(getActivity().isFinishing());
    }

    @Override
    public void onStop() {
        super.onStop();
        mLocalActivityManager.dispatchStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mLocalActivityManager.dispatchDestroy(getActivity().isFinishing());
    }
}
13
zmicer

Bonnes nouvelles de Google à ce sujet. Ils publient aujourd'hui une nouvelle API Google Maps , avec des cartes d'intérieur et MapFragment.

With this new API, adding a map to your Activity is as simple as:

<fragment
  Android:id="@+id/map"
  Android:layout_width="match_parent"
  Android:layout_height="match_parent"
  class="com.google.Android.gms.maps.MapFragment" />
4
Marcelo

L'API Google Maps ne fait pas partie de l'AOSP. Tant qu'aucun Googler ne répond, il est à peine possible de dire s'il y aura un MapFragment à l'avenir.

Une alternative limitée possible consiste à utiliser un WebViewFragment et à en abuser pour charger une URL maps.google.com Personnalisée.

2
Octavian Damiean

Voici une version MonoDroid (Mono pour Android) d'une version très simplifiée MapFragment:

public class MapFragment : Fragment
{
    // FOLLOW http://stackoverflow.com/questions/5109336/mapview-in-a-fragment-honeycomb
    private static  String KEY_STATE_BUNDLE = "localActivityManagerState";

    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        Bundle state = null;
        if (savedInstanceState != null) {
            state = savedInstanceState.GetBundle(KEY_STATE_BUNDLE);
        }
        mLocalActivityManager = new LocalActivityManager(Activity, true);
        mLocalActivityManager.DispatchCreate(state);
    }

    public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        //This is where you specify you activity class
        Intent i = new Intent(Activity, typeof(SteamLocationMapActivity)); 
        Window w = mLocalActivityManager.StartActivity("tag", i); 
        View currentView=w.DecorView; 
        currentView.Visibility = ViewStates.Visible; 
        currentView.FocusableInTouchMode = true; 
        ((ViewGroup) currentView).DescendantFocusability = DescendantFocusability.AfterDescendants;
        return currentView;
    }

    private LocalActivityManager mLocalActivityManager;
    protected LocalActivityManager GetLocalActivityManager() {
        return mLocalActivityManager;
    }   


    public override void OnSaveInstanceState(Bundle outState)
    {
        base.OnSaveInstanceState(outState);
        outState.PutBundle(KEY_STATE_BUNDLE,mLocalActivityManager.SaveInstanceState());
    }

    public override void OnResume()
    {
        base.OnResume();
        mLocalActivityManager.DispatchResume();

    }

    public override void OnPause()
    {
        base.OnPause();
        mLocalActivityManager.DispatchPause(Activity.IsFinishing);
    }

    public override void OnStop()
    {
        base.OnStop();
        mLocalActivityManager.DispatchStop();
    }
}
2

Dommage que Google n'ait pas encore répondu. FWIW si vous avez vraiment besoin de faire cela, je n'ai pas trouvé d'autre moyen que:

Faites en sorte que l'onglet Gestion de l'activité hérite de MapActivity, créez le MapView dedans par programme, faites en sorte que mapfragment.xml contienne un ViewGroup et ajoutez le MapView au ViewGroup à l'aide de

 ((ViewGroup) getFragmentManager (). FindFragmentById (R.id.Finder_map_fragment) .getView ()) addView (mapView) ;; 

Cela va clairement à l'encontre de l'idée que les fragments doivent être autonomes, mais ...

2
Valentin

Puis-je obtenir la solution:

  1. create class TempFragmentActivity étend MapActivity
  2. il y a un objet MapView dans TempFragmentActivity (comme la définition normale en xml)
  3. supprimer ce parent du formulaire d'objet MapView (LinearLayout) (annuler une exception ultérieure)
  4. garder cet objet MapView quelque part (ex: membre statique de TempFragmentActivity)
  5. dans votre fragment, ajoutez cet objet MapView à l'aide de code (ne définissez pas en xml) dans certains LinearLayout
1
Joe Zhang

Cela résout mon problème en ajoutant MapView dans des fragments. https://github.com/petedoyle/Android-support-v4-googlemaps

1
Sudhin Philip

Avec la nouvelle version d'ABS 4.0, il n'y a pas de support pour MapFragmentActivity, voici une bonne solution pour avoir une vue de carte dans un Fragment!

https://xrigau.wordpress.com/2012/03/22/howto-actionbarsherlock-mapfragment-listfragment/#comment-21

1
cesards

J'ai écrit une petite bibliothèque, écrasant les solutions basées sur LocalActivityManager au problème MapFragment (comprend également un exemple d'application montrant diverses situations d'utilisation):

https://github.com/coreform/Android-tandemactivities

0
straya