Question : How do I create a 9000 meters buffer radius from a point and display placemarks that intersect that buffer.
Answer : Google Map API for android has a class that reads and draw your current location in the map.
That class is "MyLocationOverlay". The class has a "draw" method that will be called everytime user pan or zoom on the map.
So to draw a circle radius of your current location, we need to extends this class and override its draw method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tukangandroid.tutorial; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.Point; | |
import android.graphics.Paint.Style; | |
import android.graphics.drawable.Drawable; | |
import com.google.android.maps.GeoPoint; | |
import com.google.android.maps.MapView; | |
import com.google.android.maps.MyLocationOverlay; | |
import com.google.android.maps.Projection; | |
public class MyOwnLocationOverlay extends MyLocationOverlay{ | |
private MapView mapView; | |
private Paint circlePainter; | |
private Point screenCurrentPoint; | |
private GeoPoint geoCurrentPoint; | |
private int meters; | |
public MyOwnLocationOverlay(Context context, MapView mapView) { | |
super(context, mapView); | |
this.mapView = mapView; | |
} | |
// This method is used to get user submitted radius from our application | |
public void setMeters(int meters) { | |
this.meters = meters; | |
} | |
@Override | |
public synchronized boolean draw(Canvas canvas, MapView mapView, | |
boolean shadow, long when) { | |
// Set the painter to paint our circle. setColor = blue, setAlpha = 70 so the background | |
// can still be seen. Feel free to change these settings | |
circlePainter = new Paint(); | |
circlePainter.setAntiAlias(true); | |
circlePainter.setStrokeWidth(2.0f); | |
circlePainter.setColor(0xff6666ff); | |
circlePainter.setStyle(Style.FILL_AND_STROKE); | |
circlePainter.setAlpha(70); | |
// Get projection from the mapView. | |
Projection projection = mapView.getProjection(); | |
// Get current location | |
geoCurrentPoint = getMyLocation(); | |
screenCurrentPoint = new Point(); | |
// Project the gps coordinate to screen coordinate | |
projection.toPixels(geoCurrentPoint, screenCurrentPoint); | |
int radius = metersToRadius(geoCurrentPoint.getLatitudeE6() /1000000); | |
// draw the blue circle | |
canvas.drawCircle(screenCurrentPoint.x, screenCurrentPoint.y, radius, circlePainter); | |
return super.draw(canvas, mapView, shadow, when); | |
} | |
// hack to get more accurate radius, because the accuracy is changing as the location | |
// getting further away from the equator | |
public int metersToRadius(double latitude) { | |
return (int) (mapView.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude)))); | |
} | |
} |
Then, we create our view, one map view, one textbox and one button
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="fill_parent" | |
android:layout_height="fill_parent" | |
android:stretchColumns="1"> | |
<TableRow> | |
<EditText | |
android:id="@+id/txtRadius" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:hint="Radius" | |
/> | |
<Button android:id="@+id/btnSearch" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="Search" /> | |
</TableRow> | |
<TableRow> | |
<com.google.android.maps.MapView | |
android:layout_span="2" | |
android:id="@+id/mapview" | |
android:layout_width="fill_parent" | |
android:layout_height="fill_parent" | |
android:clickable="true" | |
android:apiKey="your_api_key_here" | |
/> | |
</TableRow> | |
</TableLayout> |
After that, we need to create our main class. TukangAndroidApp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tukangandroid.tutorial; | |
import java.util.List; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.TextView; | |
import com.google.android.maps.GeoPoint; | |
import com.google.android.maps.MapActivity; | |
import com.google.android.maps.MapController; | |
import com.google.android.maps.MapView; | |
import com.google.android.maps.Overlay; | |
public class TukangAndroidApp extends MapActivity{ | |
private MapView mapView; | |
private List<Overlay> mapOverlays; | |
private MyOwnLocationOverlay myLocationOverlay; | |
private MapController mapController; | |
private TextView txtRadius; | |
private Button btnSearch; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main); | |
mapView = (MapView) findViewById(R.id.mapview); | |
mapView.setBuiltInZoomControls(true); | |
mapController = mapView.getController(); | |
btnSearch = (Button) findViewById(R.id.btnSearch); | |
btnSearch.setOnClickListener(new SearchListener()); | |
txtRadius = (TextView) findViewById(R.id.txtRadius); | |
} | |
private class SearchListener implements android.view.View.OnClickListener { | |
@Override | |
public void onClick(View v) { | |
mapView.getOverlays().clear(); | |
mapOverlays = mapView.getOverlays(); | |
myLocationOverlay = new MyOwnLocationOverlay(TukangAndroidApp.this, mapView); | |
myLocationOverlay.setMeters(Integer.parseInt(txtRadius.getText().toString())); | |
myLocationOverlay.enableCompass(); | |
myLocationOverlay.enableMyLocation(); | |
myLocationOverlay.runOnFirstFix(new Runnable() { | |
public void run() { | |
mapController.animateTo(myLocationOverlay.getMyLocation()); | |
} | |
}); | |
mapView.getOverlays().add(myLocationOverlay); | |
displayResults(); | |
} | |
} | |
private void displayResults() { | |
} | |
@Override | |
protected boolean isRouteDisplayed() { | |
return false; | |
} | |
} |
Dont forget to edit AndroidManifest.xml to add permissions and google map library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.tukangandroid.tutorial" | |
android:versionCode="1" | |
android:versionName="1.0"> | |
<application android:icon="@drawable/icon" android:label="@string/app_name"> | |
<uses-library android:name="com.google.android.maps" /> | |
<activity android:name=".TukangAndroidApp" | |
android:label="@string/app_name"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
</application> | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |
</manifest> |
Run your application.
Tips : Set the GPS location from the DDMS first before you press Search, otherwise you will encounter NullPointerException
If all goes well, your application will be like this
Notice in TukangAndroidApp.java, our displayResult method didnt do anything, so we will implement the method to return some placemarks that intersect our buffer.
First, we should extends ItemizedOverlay class to create our placemark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tukangandroid.tutorial; | |
import java.util.ArrayList; | |
import android.graphics.drawable.Drawable; | |
import com.google.android.maps.ItemizedOverlay; | |
import com.google.android.maps.OverlayItem; | |
public class HelloItemizedOverlay extends ItemizedOverlay<OverlayItem> { | |
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>(); | |
public HelloItemizedOverlay(Drawable defaultMarker) { | |
super(boundCenterBottom(defaultMarker)); | |
} | |
@Override | |
protected OverlayItem createItem(int i) { | |
return mOverlays.get(i); | |
} | |
@Override | |
public int size() { | |
return mOverlays.size(); | |
} | |
public void addOverlay(OverlayItem overlay) { | |
mOverlays.add(overlay); | |
populate(); | |
} | |
} |
Next, we will implement the displayResult method.
Our last TukangAndroidApp.java should look like this
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.tukangandroid.tutorial; | |
import java.util.ArrayList; | |
import java.util.List; | |
import android.graphics.drawable.Drawable; | |
import android.location.Location; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.TextView; | |
import com.google.android.maps.GeoPoint; | |
import com.google.android.maps.MapActivity; | |
import com.google.android.maps.MapController; | |
import com.google.android.maps.MapView; | |
import com.google.android.maps.Overlay; | |
import com.google.android.maps.OverlayItem; | |
public class TukangAndroidApp extends MapActivity{ | |
private MapView mapView; | |
private List<Overlay> mapOverlays; | |
private MyOwnLocationOverlay myLocationOverlay; | |
private MapController mapController; | |
private TextView txtRadius; | |
private Button btnSearch; | |
private boolean isFound; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main); | |
mapView = (MapView) findViewById(R.id.mapview); | |
mapView.setBuiltInZoomControls(true); | |
mapController = mapView.getController(); | |
btnSearch = (Button) findViewById(R.id.btnSearch); | |
btnSearch.setOnClickListener(new SearchListener()); | |
txtRadius = (TextView) findViewById(R.id.txtRadius); | |
} | |
private class SearchListener implements android.view.View.OnClickListener { | |
@Override | |
public void onClick(View v) { | |
mapView.getOverlays().clear(); | |
mapOverlays = mapView.getOverlays(); | |
myLocationOverlay = new MyOwnLocationOverlay(TukangAndroidApp.this, mapView); | |
myLocationOverlay.setMeters(Integer.parseInt(txtRadius.getText().toString())); | |
myLocationOverlay.enableCompass(); | |
myLocationOverlay.enableMyLocation(); | |
myLocationOverlay.runOnFirstFix(new Runnable() { | |
public void run() { | |
mapController.animateTo(myLocationOverlay.getMyLocation()); | |
} | |
}); | |
mapView.getOverlays().add(myLocationOverlay); | |
displayResults(); | |
} | |
} | |
private void displayResults() { | |
// Create dummy list of GeoPoint | |
GeoPoint point1 = new GeoPoint(35100000, 129100000); | |
GeoPoint point2 = new GeoPoint(35110000, 129110000); | |
GeoPoint point3 = new GeoPoint(35120000, 129120000); | |
List<GeoPoint> points = new ArrayList<GeoPoint>(); | |
points.add(point1); | |
points.add(point2); | |
points.add(point3); | |
mapOverlays = mapView.getOverlays(); | |
Drawable drawable = getResources().getDrawable(R.drawable.icon); | |
HelloItemizedOverlay itemizedOverlay = new HelloItemizedOverlay(drawable); | |
for(GeoPoint point : points) { | |
// Create a location because Location has a distanceTo method that we can | |
// use for buffering. Notice that distanceTo calculate distance in meter | |
Location gpsLocation = new Location("current location"); | |
// Get our current gps point and use it to create a location | |
GeoPoint currentLocation = myLocationOverlay.getMyLocation(); | |
double lat = (double) (currentLocation.getLatitudeE6() / 1000000.0); | |
double lng = (double) (currentLocation.getLongitudeE6() / 1000000.0); | |
gpsLocation.setLatitude(lat); | |
gpsLocation.setLongitude(lng); | |
Location pointLocation = new Location("point"); | |
pointLocation.setLatitude(point.getLatitudeE6() / 1000000.0); | |
pointLocation.setLongitude(point.getLongitudeE6() / 1000000.0); | |
// Calculate the distance between current location and point location | |
if(gpsLocation.distanceTo(pointLocation) < Float.parseFloat(txtRadius.getText().toString())) { | |
isFound = true; | |
OverlayItem overlayitem = new OverlayItem(point, "", ""); | |
itemizedOverlay.addOverlay(overlayitem); | |
} | |
} | |
// If any location found, draw the placemark | |
if(isFound) | |
mapOverlays.add(itemizedOverlay); | |
} | |
@Override | |
protected boolean isRouteDisplayed() { | |
return false; | |
} | |
} |
Run the application, and you can see that our application will work well.
Have fun!
Perfect........I was looking for hours this code....
ReplyDeleteHow can i get the current location
ReplyDeleteWhy does this application crashes after some time?
ReplyDelete@CEC@IT open DDMS view, click Emulator Control button (nearly top of the screen), after that you will see Location Controls.
ReplyDeletecan some one plz upload the zip file as i cant get the code working
ReplyDeleteThat was awesome
ReplyDeleteI follow your step but when I try to implement the displayResult method , It's has stopped.
Awesome! Just what I was looking for..tiny question..I need to show a list of locations surrounded by the circle definigng the radius.
ReplyDeleteWhat can I do to make sure I add the markers and draw the circle at the same time?
why does the circle disappear when I zoom passed a certain zoom level?
ReplyDeleteGreat work.. thanks a lot.... This article did many things to me...
ReplyDeletedoes it applicable in GMap v2?
ReplyDeletelike...!!!
DeleteCan you give me a full project of this application ?
ReplyDeleteI don't get it how these things work.
Can you help soving this problem http://stackoverflow.com/questions/33035373/show-markers-near-the-device-in-android/33037739#33037739 ?
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteGreat Article
ReplyDeleteJava Web Services Online Training
Web Services Course
Web Services Training Courses
Java Web Services Training in Chennai
Hi, is it possible to maybe provide us with a source code, more like a Github link if you do not mind..
ReplyDelete