«

»

jun 11 2012

OSMDROID – Introducción a OpenStreetMap en Android (OSM Parte I)

Multitud son las apps que pueblan Google Play que hacen uso de la integración de mapas en ellas y multitud de ellas, por no decir la inmensa mayoría las que hacen uso de Google Maps (en un post anterior os contabamos como usarlo) para este menester. Esto es normal teniendo en cuenta la integración del Google Maps con el SDK de Android y la fama que precede a este servicio, usado ya por miles de personas. ¿Pero es la única alternativa? ¿Es la mejor? ¿Ofrece todo lo que necesitamos? Pues no, no es la ultima alternativa y en cuanto a las otras preguntas dependerá de cada caso.

Una de estas alternativas con ciertas ventajas sobre Google Maps es OpenStreetMap un servicio de mapas de creación comunitaria, al estilo de Wikipedia. El problema es que, evidentemente, su integración con Android no es tan buena como en aquel y no existen librería oficial para tal menester, teniendo que recurrir a librería de terceros.



En este caso os presentamos OSMDROID una librería que nos ayudara a incluir estos mapas en nuestras apps, ahh y se me olvidaba, ¡permite mapas offline!

Instalación de la librería

Lo primero que deberemos hacer una vez hemos creado nuestro proyecto Android (API level 3 o superior) es bajarnos los jar necesarios:

Una vez hecho esto, como viene siendo costumbre los añadiremos al buildpath de nuestro proyecto y lo tendremos todo listo para empezar a picar código.


Nuestro primer mapa

El uso de los mapas no tiene mayor misterio que el del uso de cualquier vista mas, en este caso org.osmadroid.views.MapView. A continuación os mostramos un ejemplo con el que ya tendríamos funcionando de manera sencilla los mapas en nuestra app:



main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <org.osmdroid.views.MapView
     	android:id="@+id/openmapview"
     	android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

</LinearLayout>



MainActivity.java

import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

 private MapView myOpenMapView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        myOpenMapView = (MapView)findViewById(R.id.openmapview);
        myOpenMapView.setBuiltInZoomControls(true);
        myMapController = myOpenMapView.getController();
        myMapController.setZoom(4);
    }
}



Para que nuestro proyecto funcione correctamente es importante no olvidar configurar los permisos necesarios en el manifest:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />



Como podemos ver tenemos la posibilidad de añadir controles gracias a métodos del MapView, como por ejemplo controles zoom, o bien podemos controlarlo via código gracias a la clase MapController obtenia a través del MapView.

Una funcionalidad para mi imprescindible (es por esto que hago inciso) y que por defecto viene desactivada es el control del zoom por gestos y que podremos activar fácilmente gracias al método siguiente:

myOpenMapView.setMultiTouchControls(true);


Añadiendo información a nuestros mapas

Evidentemente, una de los principales objetivos a la hora de incluir mapas en nuestras apps es la geolocalización de puntos de interés o indicadores y por eso a continuación os contamos como incluirlos.

Para esto haremos uso de los Overlays o capas en las cuales incluiremos los elementos a mostrar. Podremos usar ItemizedIconOverlay o ItemizedOverlayWithFocus, nosotros nos centraremos en la segunda ya que nos permite la inclusión de globos de información (aunque estos dejan un poco que desear… pero no os preocupéis en un siguiente post os mostraremos como mejorarlos).



La idea es la siguiente, crearnos un array de ítems al que ir añadiendo los mismos y a partir de este crear nuestro overlay que asociaremos al mapa. A continuación os dejo el extracto de código correspondiente:


ArrayList<OverlayItem> anotherOverlayItemArray;
anotherOverlayItemArray = new ArrayList<OverlayItem>();

anotherOverlayItemArray.add(new OverlayItem("0, 0", "0, 0", new GeoPoint(0, 0)));
anotherOverlayItemArray.add(new OverlayItem("US", "US", new GeoPoint(38.883333, -77.016667)));
anotherOverlayItemArray.add(new OverlayItem("China", "China", new GeoPoint(39.916667, 116.383333)));
anotherOverlayItemArray.add(new OverlayItem("United Kingdom", "United Kingdom", new GeoPoint(51.5, -0.116667)));
anotherOverlayItemArray.add(new OverlayItem("Germany", "Germany", new GeoPoint(52.516667, 13.383333)));
anotherOverlayItemArray.add(new OverlayItem("Korea", "Korea", new GeoPoint(38.316667, 127.233333)));
anotherOverlayItemArray.add(new OverlayItem("India", "India", new GeoPoint(28.613333, 77.208333)));
anotherOverlayItemArray.add(new OverlayItem("Russia", "Russia", new GeoPoint(55.75, 37.616667)));
anotherOverlayItemArray.add(new OverlayItem("France", "France", new GeoPoint(48.856667, 2.350833)));
anotherOverlayItemArray.add(new OverlayItem("Canada", "Canada", new GeoPoint(45.4, -75.666667)));

ItemizedOverlayWithFocus<OverlayItem> anotherItemizedIconOverlay = new ItemizedOverlayWithFocus<OverlayItem>(this, anotherOverlayItemArray, myOnItemGestureListener);
myOpenMapView.getOverlays().add(anotherItemizedIconOverlay);



Como podéis comprobar en la creación del overlay hay un tercer parámetro que no hemos explicado, se trata de la clase que controlara los eventos de pulsación y que os mostramos a continuación.


OnItemGestureListener<OverlayItem> myOnItemGestureListener = new OnItemGestureListener<OverlayItem>() {

	@Override
	public boolean onItemLongPress(int arg0, OverlayItem arg1) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean onItemSingleTapUp(int index, OverlayItem item) {
		Toast.makeText(
			TestOSMActivity.this,
			item.mDescription + "n" + item.mTitle + "n"
				+ item.mGeoPoint.getLatitudeE6() + " : "
				+ item.mGeoPoint.getLongitudeE6(),
			Toast.LENGTH_LONG).show();
			
		return true;
	}

};



Como veis no tiene mayor misterio, dos métodos, para pulsación y pulsación prolongada, que configuraremos a nuestro gusto, en este caso mostrando un mensaje por pantalla con el titulo, descripción y localización.





Os hablamos acerca de los globos de información, pero si ejecutamos el código mostrado hasta ahora por mucho que pulsemos sobre nuestras marcas no aparecerá ningún globo. Esto es por que tal funcionalidad hay que activarla mediante el siguiente método:

anotherItemizedIconOverlay.setFocusItemsOnTap(true);



Por código también podremos seleccionar el elemento que deseamos:

anotherItemizedIconOverlay.setFocusedItem(0);


Pero… ¿Y si no nos gustan los iconos mostrados? No hay problema, os cuento como cambiarlos. Para cambiarlo tendríamos que crearnos nuestro propio overlay que heredara de ItemizedIconOverlay y sobreescribiera el método draw. A continuación os muestro un ejemplo de como hacerlo.


private class MyItemizedIconOverlay extends ItemizedIconOverlay<OverlayItem> {

	public MyItemizedIconOverlay(
			List<OverlayItem> pList,
			org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener<OverlayItem> pOnItemGestureListener,
			ResourceProxy pResourceProxy) {

		super(pList, pOnItemGestureListener, pResourceProxy);
		// TODO Auto-generated constructor stub

	}

	@Override
	public void draw(Canvas canvas, MapView mapview, boolean arg2) {
		// TODO Auto-generated method stub
		super.draw(canvas, mapview, arg2);

		if (this.size() > 0) {

			for (int i = 0; i < this.size(); i++) {
				GeoPoint in = getItem(i).getPoint();

				Point out = new Point();
				mapview.getProjection().toPixels(in, out);

				Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_menu_mylocation);
				canvas.drawBitmap(bm, out.x - bm.getWidth() / 2, out.y - bm.getHeight() / 2, null);
			}
		}
	}

	@Override
	public boolean onSingleTapUp(MotionEvent event, MapView mapView) {
		// TODO Auto-generated method stub
		// return super.onSingleTapUp(event, mapView);
		return true;
	}
}


El detalle principal es el hecho de saber como convertir entre la geoposición y la posición en pixeles de la pantalla, pero vemos que hay un método que lo hace por nosotros, permitiéndondos dibujar nuestro recurso (R.drawable.ic_menu_mylocation) fácilmente.


MiniMapOverlay

Como regalo final de este post os muestro un pequeño tip de como mostrar un mini mapa que hará mucho más vistosas nuestras aplicaciones.


MinimapOverlay miniMapOverlay = new MinimapOverlay(this, myOpenMapView.getTileRequestCompleteHandler());
miniMapOverlay.setZoomDifference(5);
miniMapOverlay.setHeight(200);
miniMapOverlay.setWidth(200);
myOpenMapView.getOverlays().add(miniMapOverlay);





Como podéis ver, podemos seleccionar la diferencia de zoom entre el mapa principal y el mini mapa, así como el tamaño de este. Con esto hemos acabado por hoy, en un próximo post os mostraremos el uso de los mapas offline gracias a esta librería.


Espero que os haya gustado y si es así no lo dudéis y ¡¡compartid lo aprendido!!


librería | osmdroid

Acerca del autor

JMPergar

Mobile Developer at @BeRepublic & Founder of @AndroCode. Silver Speaker & Member of Core Team at @GDGBarcelona.

  • http://sergiandreplace.com Sergiandreplace

    Imprescindible!

    Buen articulo, a ver si entre todos conseguimos expandir el uso de OSM.

    Gracias.

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      Pues si, cuanto mas seamos y mas se use, mejores seran las librerias de terceros y las opciones que estan proporcionan. O quien sabe… quizas aparezca la libreria oficial…

  • http://adaframework.com DesAndrOId

    Mola mucho el tutorial, enhorabuena,

    Pero ¿Pueden funcionar en modo Off-Line???

    XD

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      Si si, de hecho me encuentro redactando el tutorial al respecto, esto solo es el primer de tres tutoriales.

  • leon_androide

    Excelente tutorial, todo eso lo tuve que aprender sobre la marcha, no hay mucha información sobre OSM.

    Me gusto demasiado.

    Espero los demás tutoriales.

  • Marcos

    Yo siempre había usado la API de google maps… creo que ésta no se escapa sin que la pruebe… y si encima tiene modo offline… estoy deseando que saques la segunda entrega!! Enhorabuena! Me ha encantado el post!

  • Pingback: OSMDROID – Mapas offline con OpenStreetMap (OSM Parte II) | Androcode()

  • Edu

    Excelente tuto, me ha ayudado muchísimo con unas dudas que tenía.
    Para cuando un tutorial sobre geolocacion + openstreetmap. Creo que sería fantástico una tercera parte, continuación de estas dos, sobre este tema…
    O puedes aconsejarme algún link donde indagar sobre este tema… solo encuentro implementación con HTML5 en android…

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      El tema de la geolocolizacion es trivial (si ya has trabajado con ella en Google Maps), tan solo tienes que obtener la posicion y poner puntos con los overlays. No tenia planteado profuncizar en este tema, el tercer post tratara sobre una libreria que amplia la funcionalidad de esta y probablemente habra un cuarto con otra libreria que he encontrado pero que aun tengo estudiar. No descarto hacer el post que pides no obstante pero si no puedes esperar aqui tienes la version en ingles:

      http://android-er.blogspot.com.es/2012/05/display-current-location-marker-on.html

  • changoS

    Ke buenisimo tuto… me ha ayudado a solucionar algunos problemas y aprender mas… si alguien tiene algun link o material acerca del tema espero l@ pued@n compartir =)

  • Angel Alvarezr

    Muy buenas a todos.
    Lo primero, mi enhorabuena por el Tuto que esta genial.
    Segundo, ahora estoy con un proyecto de localizacion y me encuentro con varios problemas que no encuentro información. Me gustaria ir obteniendo la posición en cada momento para luego plasmarlo en el mapa creando una ruta. Existen app que hacen lo mismo (endomondo creo que es una). Para que se entienda, seria como cuando buscamos ir desde un lugar A a un lugar B en el google map..Y por otra, estoy dando la opcion para que el usuario elija utilizar el mapa por OSM o por Google.. En esto ultimo me estan dando muchos fallos..
    Por eso quisiera preguntaros como se podría hacer.

    Muchas gracias de antemano y reciban un cordial saludo.

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      En cuanto a las rutas no te puedo ayudar por que aun no he trabajado con ellas. En relaccion con la convivencia de Google Maps y OSM lo ideal es que montes cada uno en un actiity distinto, si no puedes tambien se puede hacer pero tendras problemas con clases que se llaman igual y que tendras que solucionar creando clases heredadas que lo unico que hacen es cambiar el nombre. No obstante OSMDROID ofrece un modulo para ello, aunque aún no lo he probado:

      http://code.google.com/p/osmdroid/wiki/HowToUseGoogleWrapper

  • http://www.proyectatsp.com Edgar Andres

    Hola.. Excelente tutorial…

    Tengo una pregunta que ojala me puedas resolver.

    Quiero cambiar los iconos.. pero que a su vez, pueda hacer click sobre ellos y ejectar alguna acción.

    Cuando hago lo que dices, me cambia el icono pero no puedo hacer click sobre ellos, esto debe ser porque no heredo de la clase “ItemizedOverlayWithFocus”. Cuando heredo de esta clase, no logro cambiar los iconos, no se que metodo sobreescribir.

    Gracias.

    Saludos.

    • http://www.proyectatsp.com Edgar Andres

      Listooo, solo por si alguien tiene el mismo problema que yo tuve.. dejo acá la solución:

      A cambio de usar la clase ItemizedOverlayWithFocus, use la clase ItemizedIconOverlay que se le puede enviar en el segundo parametro el drawable que queremos poner como icono, podemos ponerle el OnItemGestureListener si queremos controlar el evento click en los icono… o podemos enviarlo en null si solo queremos mostrar la posición del icono si el evento click.

      Saludos.

  • Chen

    Hola, muy bueno el tutorial.

    Solo tengo un problema, funciona todo bien, pero no puedo cambiar el icono.

    Hago la clase myitemizediconoverlay debajo de la misma activity, pero no sé como aplicarla a lo de arriba, si pongo myitemizediconoverlay en:

    ItemizedOverlayWithFocus anotherItemizedIconOverlay = new ItemizedOverlayWithFocus(this, anotherOverlayItemArray, myOnItemGestureListener);

    Tampoco me funciona, me da error.

    Gracias por la respuesta.

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      Cuando instancias anotherItemizedIconOverlay lo debes hacer de la clase myitemizediconoverlay y no de ItemizedOverlayWithFocus. Con la información que me das poco más te puedo decir.

      MyItemizedIconOverlay myItemizedIconOverlay = new MyItemizedIconOverlay(anotherOverlayItemArray, null, defaultResourceProxyImpl);

  • Carlos

    Hola primero felicidades por el tutorial pero yo tengo un inconveniente no me cargan los mapas y ya descargue las librerías .jar

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      ¿Has incluido en el manifest el permiso de acceso a internet?

  • Cristian

    Muy bueno el tutorial excelente aporte

    Solo queria hacer un comentario, para los novatos como yo

    primero no me funciono con el osmdroid-android-3.0.8.jar, tuve poner la osmdroid-android-3.0.2.jar para que los mapas se vean

    y otra es que no sabia como poner las librerias en el proyecto, vi varios tutoriales y no funcionaba. La forma correcta que me sirvio, fue la de agregar los dos archivos jar a la carpeta lib y luego hacer click derecho y elegir build pach y luego add to bouild pahc. Y funciono perfecto. Por lo menos la parte de los mapas, ahora voy con las capas. Gracias nuevamente por el aporte

  • http://basesprogramacion.blogspot.com Ricardo CD

    Hola,

    muy buen Tuto….
    Quisiera saber si pudieras poner el código del proyecto ya que así lo podríamos tomar de referencia.

    Otras vez Gracias…

    • http://basesprogramacion.blogspot.com Ricardo CD

      Me refiero al proyecto completo, debido a q hay cosas inedias que podrían sacarme de unas cuantas dudas…. Gracias..

      • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

        Lo siento no tenemos el proyecto para compartirlo, pero si tienes alguna duda pregunta sin problemas y contestaremos en la medida de lo posible.

  • Jesús

    El tutorial es buenísimo, te felicito.
    Solo un pequeño aporte (aunque no está del todo relacionado con osm), he tenido que usar una versión mas reciente de slf4j-android ( http://www.slf4j.org/android/ ) ya que tenía problemas con la que has puesto (en combinación con twitter4j para Android). Mas que nada es por si a alguien mas le pasa.
    Reitero lo dicho, un gran artículo.

  • Jesús

    He estado un poco probando y haciendo cosillas y tengo una duda: ¿puedo, al añadir por código una nueva localización, ir hacia ella de forma automáticamente? algo así como el botón de localización de gmaps. Con setfocusitem despliego el globo pero no me “muevo” hacia el.

    • Jesús

      Me respondo a mí mismo: con myMapController.setCenter(GeoPoint g) podemos centrar el mapa en la ubicación que deseemos.

  • Ivan Diaz

    Tengo un problema molesto:

    Logre cambiar el marcador o icono mostrado en el mapa de un punto.
    Pero me sale el icono que yo puse y el icono por defecto de OSM !! (salen los dos)
    Miro y miro el codigo, y no encuentro la respuesta, ojala me puedas ayudar !!

    ArrayList anotherOverlayItemArray;
    anotherOverlayItemArray = new ArrayList();

    GeoPoint geoPoint = new GeoPoint(Double.valueOf(lat),
    (Double.valueOf(lng)));

    anotherOverlayItemArray.add(new OverlayItem(“US”, “US”, geoPoint));

    DefaultResourceProxyImpl defaultResourceProxyImpl = new DefaultResourceProxyImpl(this);
    MyItemizedIconOverlay myItemizedIconOverlay = new MyItemizedIconOverlay(anotherOverlayItemArray, null, defaultResourceProxyImpl);

    myOpenMapView.getOverlays().add(myItemizedIconOverlay);

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      ¿Te salen los dos iconos a la vez? Tendría que ver tu código completo con más calma para poder ayudarte.

      • Ivan Diaz

        Exacto !!
        Me salen los dos..
        El por defecto y el que puse yo

        • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

          Es que lo que estas haciendo es crear otra capa nueva y añadirla encima, lo que tienes que hacer es recuperar la existente y modificarla.

  • Ivan Diaz

    ESo lo dedujiste viendo mi codigo??
    que realmente tengo malo en mi codigo
    SAludos

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      Entiendo que el código que me muestras es el que usas para “cambiar” el icono una vez ya tienes un overlay activo con los puntos en cuestión. Si es así aquí lo que hacer es crear un overlay nuevo añadir y el punto nuevo que quieres cambiar el icono, pero no lo cambias, lo que haces es añadir un punto nuevo en el mismas localización y en una capa distinta. No es que tu código tenga un error, no lo tiene, lo que pasa es que no estas procediendo bien.

      Si necesitas iconos distintos para distintos elementos, o bien usas varias capas para cada tipo o bien, sobrescribes el método draw de MyItemizedIconOverlay para que use uno u otro icono en función de alguna característica del item en cuestión.

      Si cambias estos iconos en tiempo de ejecución ademas tendrás que forzar a que el mapa re-dibuje las capas, si no recuerdo mal hay un método especifico para eso.

      • Ivan Diaz

        Gracias por tu respuesta.
        Lamentablemente no logré hacerlo !!
        el metodo pa redibujar el mapa es:
        mapview.invalidate();

        Saludos

  • juanito

    Hola !!
    Estoy casi terminando mi app y la desventaja en implementar estas librerias es que mi aplicacion esta bordeando los 9 megas..
    Consulta.
    Hay alguna forma de llamarlas desde internet??
    Saludos

    • http://www.linkedin.com/in/jmpergar JMPergar

      Entiendo que te ocupa eso por los mapas descargados? Por que lo que es la librería no llega a ocupar 300 KB. Si es por los mapas no hay manera de reducir ese tamaño a no ser que cambies de librería. Lo que si podrías hacer es montar algún repositorio (o los APK expansion files) para que el usuario o la app la primera vez que se ejecute descargue esos mapas, pero igualmente ese espacio será ocupado en el terminal.

      • juanito

        Por lo que dices :
        tienes algún ejemplo concreto de como hacer eso??
        me gustaría que el usuario descargara los mapas cuando instale la aplicación..
        Yo creo que es lo mas conveniente !!
        Que piensas tu ??

        Saludos

        • http://www.linkedin.com/in/jmpergar JMPergar

          Pienso que todo es relativo, depende del tamaño de los mapas, 9MB no me parece alarmante aun. En cuanto al ejemplo no tengo nada, lo que si que (espero que no dentro de mucho) quiero publicar es tutorial de como usar los APK Expansion Files pero aún no tengo nada listo.

  • amPineda

    Hola a todos,
    En primer lugar felicitarte por este o los otros manuales. Realmente me han servido de mucho.
    Y hoy en día a pocos Blogs, manuales, cursos….. que realmente sirvan.
    Tengo un pequeño problema. Que incluso ya ha sido comentado.
    Todo me funciona perfectamente… pero me muestra los dos Iconos (El personalizado y el Estándar).
    ¿Me puedes echar una mano con esto?

    Gracias por todo.

    Este es mi código:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.isismap_activity);
           
            //*** Crear el mapa y establecer sus propiedades.        
            mainMap = (MapView)findViewById(R.id.openmapview);
            mainMap.setBuiltInZoomControls(true);
            mainMap.setMultiTouchControls(true);            
                   
            mMapController = mainMap.getController();
            mMapController.setZoom(12);
            mMapController.setCenter(new GeoPoint(40.234853, -4.02696));
    ........


     /***
         * Función que permite pintar los puntos en el mapa.
         * @param puntos Puntos geográficos que se deben pintar
         */
        public void PintarWayPoints(geoInfo [] puntos){
            ArrayList<OverlayItem> puntosMap;
           
            //ArrayList<OverlayItem> anotherOverlayItemArray;
            //anotherOverlayItemArray = new ArrayList<OverlayItem>();
           
           
            try{       
                puntosMap = new ArrayList<OverlayItem>();
                String info;
               
                if (puntos != null ){          
                    for (int i = 0; i < GPSIndex; i++){
                       
                        info = "Alt: " + puntos[i].getAltitude() + " Spd: " + puntos[i].getSpeed() + " Crs: " + puntos[i].getCourse();             
                        puntosMap.add(new OverlayItem ("Tecnam MRI (EO-FIN)", info, new GeoPoint(puntos[i].getLatDD(), puntos[i].getLonDD())));
                    }
                }
                else{
                    puntosMap.add((new OverlayItem ("Collado Villalba", "", new GeoPoint(40.64733, -3.97799))));
                    puntosMap.add(new OverlayItem("US", "US", new GeoPoint(38.883333, -77.016667)));               
                }
           
                //ItemizedOverlayWithFocus<OverlayItem> iconos = new ItemizedOverlayWithFocus<OverlayItem>(this, puntosMap, mapOnItemGestureListener);     
                DefaultResourceProxyImpl defaultResourceProxyImpl = new DefaultResourceProxyImpl(this);
                MyItemizedIconOverlay iconos = new MyItemizedIconOverlay(puntosMap, mapOnItemGestureListener, defaultResourceProxyImpl);
                           
                mainMap.getOverlays().add(iconos);
               
            }
            catch (Exception er){
                System.out.println(er.getMessage());
            }      
                   
        }


    /***
         * PERSONALIZAR ICONOS
         *
         */
        private class MyItemizedIconOverlay extends ItemizedIconOverlay<OverlayItem> {
             
            public MyItemizedIconOverlay(
                    List<OverlayItem> pList,
                    org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener<OverlayItem> pOnItemGestureListener,
                    ResourceProxy pResourceProxy) {
         
                super(pList, pOnItemGestureListener, pResourceProxy);
                // TODO Auto-generated constructor stub
         
            }
         
            @Override
            public void draw(Canvas canvas, MapView mapview, boolean arg2) {
                // TODO Auto-generated method stub
                super.draw(canvas, mapview, arg2);
         
                if (this.size() > 0) {
         
                    for (int i = 0; i < this.size(); i++) {
                        GeoPoint in = getItem(i).getPoint();
         
                        Point out = new Point();
                        mapview.getProjection().toPixels(in, out);
         
                        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.air_force);
                        canvas.drawBitmap(bm, out.x - bm.getWidth() / 2, out.y - bm.getHeight() / 2, null);
                    }
                }
            }
         
            @Override
            public boolean onSingleTapUp(MotionEvent event, MapView mapView) {
                // TODO Auto-generated method stub
                // return super.onSingleTapUp(event, mapView);
                return true;
            }
        }
    • http://www.linkedin.com/in/jmpergar JMPergar

      Así a bote pronto se me ocurre que no llames al método padre en el onDraw si vas a pintar tu el punto, puede ser que este aquí el problema de que te lo dibuje dos veces.

  • Iván

    Buenas, en primer lugar agradecer el trabajo por este excelente tutorial.

    Tengo el mismo problema que amPineda, y he probado la solución que has dado sobre no llamar al método draw, y efectivamente, desaparece el icono original, mostrando sólamente el que nosotros definimos, pero el problema es que ahora al hacer click sobre estos iconos, no se muestra la información de los globos. ¿A qué puede ser debido?.

    Muchas gracias de antemano.

  • juan diaz

    No te pasó esto alguna vez ??
    en realidad es bastante molestoso y no se como solucionarlo..
    http://stackoverflow.com/questions/13773256/org-osmdroid-views-mapview-failed-to-instantiate

    Espero tu respuesta.

    • Bruno

      No has puesto todos los permisos requeridos por OSM. Me paso exactamente lo mismo.

      • Bruno

        Se me olvido pegarlos

  • Albe

    Buen tutorial, pero hay algun problema con las libreria que dices no se visualiza el mapa en el emulador, en un dispositivo fisico si que funciona.

    Un saludo.

  • Carlos

    Albe, el simulador que usas de android lo simulaste como si tuviese tarjeta sd? a mi en su día me fallaba por eso.

    un saludo y gracias por el tutorial!!

  • Marcelo

    cuando pongo el codigo del main.xml me sale error
    The following classes could not be instantiated:
    - org.osmdroid.views.MapView (Open Class, Show Error Log)
    See the Error Log (Window > Show View) for more details.
    Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse
    y no se xq pero ya intente de todo, una ayuda.

    • Bruno

      Hola Marcelo no has importado las librerias
      osmdroid-android-3.0.8.jar
      slf4j-android-1.5.8.jar
      Si las has importado mediante eclipse, puede que te de error. Lo mejor es las metas a mano en la carpte libs de su proyecto. Worspace->miProyecto->libs->”pegalas aquí” (normalmente estara en tu c->users->tuusarioç

      Un saludo

      Por cierto genial el post me ha ayudado mucho.

  • https://plus.google.com/116437354986484103506 David Untama

    en la primera vista de el código en MainActivity faltaría declarar
    private MapController myMapController;
    y agregar un cast al momento de crear un controlador de mapa
    myMapController = (MapController) myOpenMapView.getController();

  • Diego

    Buenas, muy bueno el tutorial! solo una cosilla y una duda:
    - Al principio no me dibujaba el mapa, y estuve googleando y finalmente encontré que para la versión 3.0.8 de osmdroid no funciona el MAPNIK, hay que usar: mMapView.setTileSource(TileSourceFactory.MAPQUESTOSM);
    o bien actualizar a la version 4.1 (que es lo que yo hice despues de probar ambos métodos)

    Y ahora mi duda:

    estoy pintando un punto correctamente tal y como tu nos has dicho, pero ahora me gustaría que el usuario pudiese cambiar ese punto haciendo LongClick en el mapa….
    con este post: http://stackoverflow.com/questions/1678493/android-maps-how-to-long-click-a-map implementé un handler y efectivamente puedo capturar el longclick en el mapa, pero solo tengo el MotionEvent que lo produjo y no el punto del mapa para poder hacer una proyeccion a GeoPoint.

    ¿Se te ocurre alguna forma de poder hacer esto?

    Muchas gracias por todo!

    • javier

      Hola. A mi tampoco me dibuja el mapa. Ni en el emulador, ni el teléfono. Solo me muestra la cuadrícula blanca vacía. ¿Cómo lo solucionaste?

  • Diego

    Hola, soy yo otra vez. :)

    Finalmente he solucionado el problema del longpress con el osmbonuspack (https://code.google.com/p/osmbonuspack). De momento lo recomiendo al 100%.

    Otro detalle a tener en cuenta es que según los términos de uso de google, el Geocoder solo se puede usar en mapas de Google, por lo que en este ejemplo se está violando dicho término. El bonuspack también tiene geocoder, así que recomiendo echarle un vistazo si se va a usar openstreetmaps.

    Un saludo!

  • Nicolas

    muy bueno el tuto! me sirvio mucho!
    Tengo un problema o un comportamiento extraño… resulta que luego de agregarle los iconos al mapa con myOpenMapView.getOverlays().add(anotherItemizedIconOverlay); no me aparecen dibujados sino hasta que hago algun momiento en el mapa (hago zoom por ejemplo, o lo muevo un poco).
    Alguien sabe que puede ser?

    gracias

  • Enrique

    Hola, esta muy bien. soy novato en estos temas de geolocalizacion, tengo duda en la seccion de un Toast. El conexto hace referencia hacia una clase que no la especifican.
    agredeceria que me digan cuantas clases se usan en el tuto.
    y otra mas podrian publicar el codigo fuente, para que sea mas sencillo de seguir,
    Gracias

  • Andrea

    Mira estoy diseñando una aplicación para ciclovías, yo podria usar el OSM solo para que me muestre las cilcorutas de una ciudad??

  • javier

    Hola. A mi me muestra el mapa en blanco, tanto en el emulador como en el teléfono. ¿cómo lo solucionaron? Gracias!!

  • Rigo

    Hola excelente manual y mas para mi que estoy empezando en estos temas. Tengo una duda, puse un boton sobre el mapa y deseo que cuando de click sobre él desaparecer un OverlayItem. He puesto al boton un setOnClickListener de esta forma pero al dar click no pasa absutamete nada.

    final Button button = (Button) findViewById(R.id.remueve);
    button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v ) {
    HotelesOverlayItemArray.remove(0);
    }
    });

    Como se hace para activar y desactivar las capas. Saludos