Wednesday, May 16, 2012

Display current location marker on OpenStreetMap


Further works on last exercise "Add Scale Bar on OpenStreetMap", add a marker on OpenStreetMap, to indicate the current location.

Display current location marker on OpenStreetMap


Copy your marker drawing in the folder /res/drawable/. You can find number of Android icons in installed SDK directory: /android-sdks/platforms/<android version>/data/res/

overlayItemArray is a array of OverlayItem, it have none or ONE item of current location only.

In this exercise, create custom MyItemizedIconOverlay class extends from MyItemizedIconOverlay. Then add the MyItemizedIconOverlay object (myItemizedIconOverlay) to the MapView overlay. Refer to the code below the comment "//--- Create Overlay".

To update the item(s) in overlayItemArray, simple use methods of clear(), add()...etc. Refer to the method setOverlayLoc(Location overlayloc).

In the custom ItemizedIconOverlay class, MyItemizedIconOverlay; I override onSingleTapUp() method to return true always - Because the app will FORCE CLOSE without it! (I don't know why at this moment)

Modify AndroidOpenStreetMapViewActivity.java. Other files refer to previous exercises.

package com.exercise.OpenStreetMapView;

import java.util.ArrayList;
import java.util.List;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.OverlayItem;
import org.osmdroid.views.overlay.ScaleBarOverlay;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.MotionEvent;

public class AndroidOpenStreetMapViewActivity extends Activity {
 
 private MapView myOpenMapView;
 private MapController myMapController;
 
 LocationManager locationManager;
 
 ArrayList<OverlayItem> overlayItemArray;
 
    /** 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(12);
        

        //--- Create Overlay
        overlayItemArray = new ArrayList<OverlayItem>();
        
        DefaultResourceProxyImpl defaultResourceProxyImpl 
         = new DefaultResourceProxyImpl(this);
        MyItemizedIconOverlay myItemizedIconOverlay 
         = new MyItemizedIconOverlay(
           overlayItemArray, null, defaultResourceProxyImpl);
        myOpenMapView.getOverlays().add(myItemizedIconOverlay);
        //---

        
        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        
        //for demo, getLastKnownLocation from GPS only, not from NETWORK
        Location lastLocation 
         = locationManager.getLastKnownLocation(
           LocationManager.GPS_PROVIDER);
        if(lastLocation != null){
         updateLoc(lastLocation);
        }
        
        //Add Scale Bar
        ScaleBarOverlay myScaleBarOverlay = new ScaleBarOverlay(this);
        myOpenMapView.getOverlays().add(myScaleBarOverlay);
    }
    
    @Override
 protected void onResume() {
  // TODO Auto-generated method stub
  super.onResume();
  locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, myLocationListener);
  locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, myLocationListener);
 }

 @Override
 protected void onPause() {
  // TODO Auto-generated method stub
  super.onPause();
  locationManager.removeUpdates(myLocationListener);
 }

 private void updateLoc(Location loc){
     GeoPoint locGeoPoint = new GeoPoint(loc.getLatitude(), loc.getLongitude());
     myMapController.setCenter(locGeoPoint);
     
     setOverlayLoc(loc);
     
     myOpenMapView.invalidate();
    }
 
 private void setOverlayLoc(Location overlayloc){
  GeoPoint overlocGeoPoint = new GeoPoint(overlayloc);
  //---
     overlayItemArray.clear();
     
     OverlayItem newMyLocationItem = new OverlayItem(
       "My Location", "My Location", overlocGeoPoint);
     overlayItemArray.add(newMyLocationItem);
     //---
 }
    
    private LocationListener myLocationListener
    = new LocationListener(){

  @Override
  public void onLocationChanged(Location location) {
   // TODO Auto-generated method stub
   updateLoc(location);
  }

  @Override
  public void onProviderDisabled(String provider) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public void onProviderEnabled(String provider) {
   // TODO Auto-generated method stub
   
  }

  @Override
  public void onStatusChanged(String provider, int status, Bundle extras) {
   // TODO Auto-generated method stub
   
  }
     
    };
    
    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(!overlayItemArray.isEmpty()){
    
    //overlayItemArray have only ONE element only, so I hard code to get(0)
    GeoPoint in = overlayItemArray.get(0).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,  //shift the bitmap center
      out.y - bm.getHeight()/2,  //shift the bitmap center
      null);
   }
  }

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


Download the files.

Next:
- Create multi-marker OpenStreetMap for Android


9 comments:

  1. Hi..

    Your explanation with examples are wonderful, but when i run your projects with osmdroid-android-3.0.8.jar tiles are not loading.. Tiles are loading for me with 3.0.1 only, but i m loosing 3.0.8 features.
    I want to run all your projects, please give a sol'n to load tiles faster.
    Thanks in advance.

    ReplyDelete
  2. If I do these steps, I get 2 markers drawn at my overlayitems. The one from getResources() but also the standard marker. How do I remove the standard marker?

    ReplyDelete
  3. This downloaded code run... but i can not see map..what is the problem...

    ReplyDelete
  4. This downloaded code run... but i can not see map..what is the problem...

    same here..

    ReplyDelete
  5. Please Load the Map Tilesfrom local DB. using overlay Item. in this code they did not mention this Map overlay, Please refer Map Tile Loading samples, I'm Sure the code is worked for me.

    ReplyDelete
  6. hi

    i have a problem with the code, when i start the app in a emulator the app stops any ideias.

    ReplyDelete
  7. thx for the explanation.But i've got a problem when i tap/click my map. It will throw java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0.

    Its still fine, if i just drag the map. And only crash if i tap/click the map after marker appear. Any advice . . . .

    ReplyDelete
  8. Does this code follow user's location if the user is moving?

    ReplyDelete
  9. People who can't see map tiles, you have to call setTileSource() method, after finding mapview like this; YOUR_MAPVIEW.setTileSource(TileSourceFactory.MAPQUESTOSM);

    ReplyDelete