studio programacion herramientas fundamentos con avanzado aplicaciones android google-maps android-fragments android-maps android-3.0-honeycomb

programacion - manual de android en pdf



MapView en un fragmento(Honeycomb) (12)

ahora que el último SDK está disponible con google apis, ¿cuál es la mejor manera de crear un Fragment con MapView? MapView necesita una MapActivity para funcionar correctamente.

Tener la Actividad administrando los Fragmentos hereda de MapActivity (mala solución porque va en contra de la idea de que los Fragmentos sean autosuficientes) y use un diseño basado en xml regular no funciona. Obtengo una NullPointerException en MapActivity.setupMapView ():

E/AndroidRuntime( 597): Caused by: java.lang.NullPointerException E/AndroidRuntime( 597): at com.google.android.maps.MapActivity.setupMapView(MapActivity.java:400) E/AndroidRuntime( 597): at com.google.android.maps.MapView.(MapView.java:289) E/AndroidRuntime( 597): at com.google.android.maps.MapView.(MapView.java:264) E/AndroidRuntime( 597): at 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 de MapView. No funciona:

E/AndroidRuntime( 834): Caused by: java.lang.IllegalArgumentException: MapViews can only be created inside instances of MapActivity. E/AndroidRuntime( 834): at com.google.android.maps.MapView.(MapView.java:291) E/AndroidRuntime( 834): at com.google.android.maps.MapView.(MapView.java:235) E/AndroidRuntime( 834): at de.foo.FinderMapFragment.onCreateView(FinderMapFragment.java:225) E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:708) E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:900) E/AndroidRuntime( 834): at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:978) E/AndroidRuntime( 834): at android.app.Activity.onCreateView(Activity.java:4090) E/AndroidRuntime( 834): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664)

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

Gracias y saludos desde Alemania, Valentin


¿Puedo obtener la solución?

  1. crear clase TempFragmentActivity extiende MapActivity
  2. hay un objeto MapView dentro de TempFragmentActivity (como definición normal en xml)
  3. eliminar este formulario de objeto MapView primario (LinearLayout) (excepción de vacío posterior)
  4. Mantenga este objeto MapView en algún lugar (ej: miembro estático de TempFragmentActivity)
  5. en su Fragmento, agregue este objeto MapView usando código (no defina en xml) en LinearLayout

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 con la nueva API: https://developers.google.com/maps/documentation/android/start#add_a_map

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

Así que ahora puedes simplemente usar la clase de fragmento "com.google.android.gms.maps.MapFragment". Mostrará el mapa en tu 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"/>


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

public class MapFragment : Fragment { // FOLLOW http://.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(); } }


Buenas noticias de Google sobre esto. Están lanzando hoy una nueva API de Google Maps , con mapas 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" />


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

Sin embargo, también hay un inconveniente:

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



Es una pena que Google aún no haya respondido. FWIW si realmente necesita hacer esto, no encontré otra manera que no sea:

Haga que la actividad de administración de pestañas herede MapActivity, cree MapView allí programáticamente, haga que mapfragment.xml contenga un ViewGroup y agregue MapView al ViewGroup usando

((ViewGroup) getFragmentManager().findFragmentById(R.id.finder_map_fragment).getView()).addView(mapView);;

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




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

Una posible alternativa limitada es usar un WebViewFragment y abusar de él para cargar una URL personalizada de maps.google.com .


Logré resolver esto usando TabHost en fragmento.

Aquí está la idea (brevemente):

  1. MainFragmentActivity extiende FragmentActivity (desde la biblioteca de soporte) y tiene MapFragment .

  2. MyMapActivity extiende MapActivity y contiene MapView .

  3. LocalActivityManagerFragment hosts LocalActivityManager

  4. MapFragment extiende MapFragment .

  5. Y MyMapActivity contiene la actividad MyMapActivity en él.

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


Solo para aclarar la respuesta. Intenté el enfoque sugerido por inazaruk y ChristophK. De hecho, puedes ejecutar cualquier actividad en un fragmento, no solo en 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()); } }