MapView en un fragmento (panal)

81

Ahora que el SDK final está disponible con las API de Google, ¿cuál es la mejor manera de crear un Fragmento con MapView? MapView necesita MapActivity para funcionar correctamente.

Tener la actividad que administra los fragmentos heredada de MapActivity (mala solución porque va en contra de la idea de que los fragmentos son autónomos) y usar un diseño regular basado en xml no funciona. Obtengo una NullPointerException en MapActivity.setupMapView ():

E / AndroidRuntime (597): causado por: java.lang.NullPointerException
E / AndroidRuntime (597): en com.google.android.maps.MapActivity.setupMapView (MapActivity.java:400)
E / AndroidRuntime (597): en com.google.android.maps.MapView. (MapView.java:289)
E / AndroidRuntime (597): en com.google.android.maps.MapView. (MapView.java:264)
E / AndroidRuntime (597): en com.google.android.maps.MapView. (MapView.java:247)

Mi segunda idea fue crear MapView mediante programación y pasar la actividad asociada (a través de getActivity ()) como Contexto al constructor MapView. No funciona:

E / AndroidRuntime (834): Causado por: java.lang.IllegalArgumentException: MapViews solo se puede crear dentro de instancias de MapActivity.
E / AndroidRuntime (834): en com.google.android.maps.MapView. (MapView.java:291)
E / AndroidRuntime (834): en com.google.android.maps.MapView. (MapView.java:235)
E / AndroidRuntime (834): en de.foo.FinderMapFragment.onCreateView (FinderMapFragment.java:225)
E / AndroidRuntime (834): en android.app.FragmentManagerImpl.moveToState (FragmentManager.java:708)
E / AndroidRuntime (834): en android.app.FragmentManagerImpl.moveToState (FragmentManager.java:900)
E / AndroidRuntime (834): en android.app.FragmentManagerImpl.addFragment (FragmentManager.java:978)
E / AndroidRuntime (834): en android.app.Activity.onCreateView (Activity.java:4090)
E / AndroidRuntime (834): en android.view.LayoutInflater.createViewFromTag (LayoutInflater.java:664)

Realmente debería haber algo como MapFragment que se encargue de los subprocesos de fondo que necesita MapView, supongo ... Entonces, ¿cuál es la mejor práctica actual para hacer esto?

Gracias y saludos desde Alemania, Valentin

Valentin
fuente
2
Informé una solicitud de función para esto. Por favor, destaque. code.google.com/p/android/issues/detail?id=15347
Jeremy Edwards

Respuestas:

8

A partir del 03.12.2012, Google lanzó Google Maps Android API v2 . Ahora puedes olvidarte de estos problemas. https://developers.google.com/maps/documentation/android/

Ejemplo usando una nueva API: https://developers.google.com/maps/documentation/android/start#add_a_map

Esta API funcionará al menos para la API 8 de Android, así que úsala;).

Así que ahora puede simplemente usar la clase de fragmento "com.google.android.gms.maps.MapFragment". Mostrará el mapa en su Actividad. Ejemplo de diseño del enlace de arriba:

<?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"/>
Paul Annekov
fuente
87

Me las arreglé para resolver esto usando TabHost en fragmento.

Aquí está la idea (brevemente):

  1. MainFragmentActivityextiende FragmentActivity(de la biblioteca de soporte) y tiene MapFragment.

  2. MyMapActivityextiende MapActivityy contiene MapView.

  3. LocalActivityManagerFragment Hospedadores LocalActivityManager

  4. MapFragmentse extiende LocalActivityManagerFragment.

  5. Y LocalActivityManagercontiene MyMapActivityactividad en él.

Implementación de ejemplo: https://github.com/inazaruk/map-fragment .


ingrese la descripción de la imagen aquí

inazaruk
fuente
4
Si luego desea que MapActivity pueda comunicarse con la actividad principal (que es fácil con un fragmento), puede usar Activity.getParent ()
Dori
3
Realmente no necesita usar un TabHost, también puede usar un LocalActivityManager y adjuntar la ventana devuelta al contenido de su fragmento
ChristophK
4
En caso de que alguien más se esté preguntando, aquí está el código:Intent i = new Intent(getActivity().getParent(), MyMapActivity.class); Window w = localActivityManager.startActivity("tag", i); currentView=w.getDecorView(); currentView.setVisibility(View.VISIBLE); currentView.setFocusableInTouchMode(true); ((ViewGroup) currentView).setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); this.contentView.addView(currentView);
ChristophK
8
tenga cuidado,
LocalActivityManager
4
Me funciona bien, usando pestañas y fragmentos. Para aquellos que preguntan sobre la explicación, prefiero ver el proyecto y su código, es fácil de entender. Y sí, LocalActivityManagerestá desaprobado, pero esto es solo un truco, este problema se resolverá adecuadamente cuando decidan incluir el soporte adecuado para Mapas dentro de Fragmentos.
mdelolmo
23

Como se discutió en Google Groups , Peter Doyle construyó una biblioteca de compatibilidad personalizada que también admite Google Maps. android-support-v4-googlemaps

Sin embargo, también hay una desventaja:

Actualmente, una desventaja es que TODAS las clases que extienden FragmentActivity son MapActivitys. Es posible hacer una clase separada (es decir, FragmentMapActivity), pero requiere cierta refactorización del código FragmentActivity.

TomTasche
fuente
6
Esto también significa que su aplicación no estará actualizada con la biblioteca de soporte más reciente. Si bien android-support-v4-googlemaps se ha actualizado varias veces, actualmente tiene 2 versiones por detrás. Estoy de acuerdo con otros en que esta biblioteca modificada es un truco más grande que usar LocalActivityManager en desuso.
Stan Kurdziel
1
github.com/petedoyle/android-support-v4-googlemaps está actualizado ahora (r10 a partir de este mensaje). También he refactorizado las cosas para que sea muy fácil mantenerlo actualizado en el futuro.
Pete Doyle
Tengo una pregunta. Si la aplicación ya está implementada e instalada, ¿cuál es la desventaja de "no estar actualizado con la biblioteca de soporte más reciente"?
hendrix
El problema principal con este enfoque, en mi opinión, es que no podrá implementar su aplicación con el soporte opcional de Maps. Dado que todas las FragmentActivities amplían MapActivity, simplemente se bloqueará en dispositivos sin API de Google (por ejemplo, Kindle Fire).
Paul Lammertsma
13

Solo para aclarar la respuesta. Probé el enfoque sugerido por inazaruk y ChristophK. En realidad, puede ejecutar cualquier actividad en un fragmento, no solo Google Maps. Aquí está el código que implementa la actividad del mapa de Google como un fragmento gracias a inazaruk y 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());
    }
}
zmicer
fuente
2
Pero la única solución que evita LocalActivityManager(como se comenta aquí: code.google.com/p/android/issues/detail?id=15347 ) implica extender todo FragmentActivities , lo que parece aún menos óptimo.
Estel
LocalActivityManager está más desaprobado porque ActivityGroup está desaprobado, sigue siendo útil para esta situación y posiblemente Google lo pensará dos veces antes de eliminarlo en futuras versiones si las personas lo están usando para resolver sus deficiencias.
straya
4

Buenas noticias de Google sobre esto. Hoy están lanzando una nueva API de Google Maps , con mapas de interiores y 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" />
Marcelo
fuente
No exactamente. Intente usar eso en un FragmentPagerAdapter.
Thomas Dignan
Si estás hablando de la vista en negro, hay un pequeño truco para solucionarlo stackoverflow.com/questions/13837697/…
Marcelo
Gracias. Terminé viendo eso más tarde, pero ahora estoy usando la primera versión de la API de mapas con polaris.
Thomas Dignan
2

La API de Google Maps no forma parte del AOSP. Mientras ningún Googler responda, apenas es posible saber si habrá un MapFragment en el futuro.

Una posible alternativa limitada es usar WebViewFragmenty abusar de él para cargar una maps.google.comURL personalizada .

Octavian A. Damiean
fuente
1
¡Esperamos que la API de mapas se actualice pronto con fragmentos y el dibujo vectorial!
Nathan Schwermann
2

Lástima que Google no haya respondido todavía. FWIW si realmente necesitas hacer esto, no encontré otra manera que:

Haga que la actividad de gestión de pestañas herede de MapActivity, cree MapView allí mediante programación, haga que mapfragment.xml contenga un ViewGroup y agregue MapView al ViewGroup

((ViewGroup) getFragmentManager (). FindFragmentById (R.id.finder_map_fragment) .getView ()). AddView (mapView) ;;

Claramente, esto va fuertemente en contra de la idea de que los fragmentos deben ser autónomos pero ...

Valentin
fuente
Gracias, hacer que la actividad de administración de fragmentos extienda MapActivity funcionó perfectamente para mí.
Pete Doyle
2

Aquí hay una versión MonoDroid ( Mono para Android ) de un MapFragment muy simplificado :

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();
    }
}
Ian Vink
fuente
1

¿Puedo obtener la solución?

  1. crear clase TempFragmentActivity extiende MapActivity
  2. hay un objeto MapView dentro de TempFragmentActivity (como la definición normal en xml)
  3. eliminar este objeto MapView del formulario principal (LinearLayout) (anular la excepción posterior)
  4. mantenga este objeto MapView en algún lugar (por ejemplo: miembro estático de TempFragmentActivity)
  5. en su Fragmento, agregue este objeto MapView usando código (no defina en xml) en algún LinearLayout
Joe Zhang
fuente