Abstract
The DrivingDirection package (com.google.googlenav.DrivingDirection) is removed since Android SDK 1.1. However, in this article, I will show you how to adopt driving direction function in MapView object without the DrivingDirection package.
摘要
地圖駕駛導航的功能在Android SDK 1.1以後已經被移除,不過這篇文章我將會展示如何在沒有DrivingDirection這個package的情況下,依然可以使用駕駛導航的功能,必且顯示在MapView物件。
1. Prepare the map resource and Internet accessibility.
1.1 Open the main.xml file in layout directory, and add a map reource in the file.
| XML: |
| <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.google.android.maps.MapView android:id="@+id/myMapView1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_x="0px" android:enabled="true" android:clickable="true" android:apiKey="0mRN-6bSm63hZJtPZSmcjoZAzdCztLnZv-O4SZw" android:layout_y="105px"> </com.google.android.maps.MapView> </LinearLayout> |
1.1.1 You have to apply a android map api key for your computer. Find the debug.keystore path in Eclpise(Window->Rreferences).
1.1.2 In cmd console, type
| cmd: |
| keytool -list -alias androiddebugkey -keystore "C:\Documents and Settings\Administrator\Local Settings\Application Data\ Android\debug.keystore" -storepass android -keypass android |
1.1.3 Go to http://code.google.com/intl/zh-TW/android/maps-api-signup.html ,type your MD5 fingerprint, so that you can get the map api key as follow.
1.2 Open AndroidManifest.xml, add
<uses-library android:name="com.google.android.maps"/>
and
<uses-permission android:name="android.permission.INTERNET" />
Therefore, the file would be something like:
| XML: |
| <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.goolge" android:versionCode="1" android:versionName="1.0.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".RoutePath" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <uses-library android:name="com.google.android.maps"/> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest> |
2. Draw the route path in your map.
2.1 Get KML route file from google.
For a normal user, the google maps help them get the route path in map figures. However, we would like to get the KML file of the route path. I found a parameter in the google map URL controls the output type.
- output= Output format (blank (default) is a standard webpage for user)
- output=html Uses the old style Google Local page format from before it merged with Google Maps, with the small map and large sidebar.
- output=js Outputs JavaScript object literals and function calls used by Google Maps, including encoded polyline data for driving directions, and stage information in HTML format.
- output=kml Outputs a KML file containing information representing the current map. (works with Normal Searches, Directions and MyMaps)
- output=nl Outputs a small KML file containing a NetworkLink wrapper linking to a URL from which Google Earth and Google Maps can obtain the information (only known to work with MyMaps).
- output=embed Outputs HTML suitable for embedding in third party sites, only works with the presence of the encrypted s= param, presumably to stop arbitrary content being included.
- output=dragdir returns a JSON object that contains the reverse geocode and a an encoded polyline for a given saddr (start point of the route) and daddr (endpoint of the route)
- output=georss (Geo)RSS output for the current map - probably only MyMaps
And the latitude and longitude of source and destination are determined by saddr and daddr parameter, respectively.
For example, a route KML file can be accessed through this URL:
http://maps.google.com/maps?f=d&hl=en&saddr=25.04202,121.534761&daddr=25.05202,121.554761&ie=UTF8&0&om=0&output=kml
In the KML file, each point in the route path is shown in terms of (longitude, latitude, heigth).
2.2 Create DrawPath(…) in your activity. This function do the following procedure.
a) Building the URL from src and dest.
b) Connecting to the URL and create a DocumentBuilder to parse the KML file.
c) Split each point in the path and draw each the line on the mMapView01.
| Java: |
| private void DrawPath(GeoPoint src,GeoPoint dest, int color, MapView mMapView01) { // connect to map web service StringBuilder urlString = new StringBuilder(); urlString.append("http://maps.google.com/maps?f=d&hl=en"); urlString.append("&saddr=");//from urlString.append( Double.toString((double)src.getLatitudeE6()/1.0E6 )); urlString.append(","); urlString.append( Double.toString((double)src.getLongitudeE6()/1.0E6 )); urlString.append("&daddr=");//to urlString.append( Double.toString((double)dest.getLatitudeE6()/1.0E6 )); urlString.append(","); urlString.append( Double.toString((double)dest.getLongitudeE6()/1.0E6 )); urlString.append("&ie=UTF8&0&om=0&output=kml"); Log.d("xxx","URL="+urlString.toString()); // get the kml (XML) doc. And parse it to get the coordinates(direction route). Document doc = null; HttpURLConnection urlConnection= null; URL url = null; try { url = new URL(urlString.toString()); urlConnection=(HttpURLConnection)url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.setDoOutput(true); urlConnection.setDoInput(true); urlConnection.connect(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(urlConnection.getInputStream()); if(doc.getElementsByTagName("GeometryCollection").getLength()>0) { //String path = doc.getElementsByTagName("GeometryCollection").item(0).getFirstChild().getFirstChild().getNodeName(); String path = doc.getElementsByTagName("GeometryCollection").item(0).getFirstChild().getFirstChild().getFirstChild().getNodeValue() ; Log.d("xxx","path="+ path); String [] pairs = path.split(" "); String[] lngLat = pairs[0].split(","); // lngLat[0]=longitude lngLat[1]=latitude lngLat[2]=height // src GeoPoint startGP = new GeoPoint((int)(Double.parseDouble(lngLat[1])*1E6),(int)(Double.parseDouble(lngLat[0])*1E6)); mMapView01.getOverlays().add(new MyOverLay(startGP,startGP,1)); GeoPoint gp1; GeoPoint gp2 = startGP; for(int i=1;i<pairs.length;i++) // the last one would be crash { lngLat = pairs[i].split(","); gp1 = gp2; // watch out! For GeoPoint, first:latitude, second:longitude gp2 = new GeoPoint((int)(Double.parseDouble(lngLat[1])*1E6),(int)(Double.parseDouble(lngLat[0])*1E6)); mMapView01.getOverlays().add(new MyOverLay(gp1,gp2,2,color)); Log.d("xxx","pair:" + pairs[i]); } mMapView01.getOverlays().add(new MyOverLay(dest,dest, 3)); // use the default color } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } |
2.3 Adding MyOverlay class – Drawing the points and lines on the ViewMap.
| Java: |
| package com.goolge; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.RectF; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; public class MyOverLay extends Overlay { private GeoPoint gp1; private GeoPoint gp2; private int mRadius=6; private int mode=0; private int defaultColor; private String text=""; private Bitmap img = null; public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode) // GeoPoint is a int. (6E) { this.gp1 = gp1; this.gp2 = gp2; this.mode = mode; defaultColor = 999; // no defaultColor } public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode, int defaultColor) { this.gp1 = gp1; this.gp2 = gp2; this.mode = mode; this.defaultColor = defaultColor; } public void setText(String t) { this.text = t; } public void setBitmap(Bitmap bitmap) { this.img = bitmap; } public int getMode() { return mode; } @Override public boolean draw (Canvas canvas, MapView mapView, boolean shadow, long when) { Projection projection = mapView.getProjection(); if (shadow == false) { Paint paint = new Paint(); paint.setAntiAlias(true); Point point = new Point(); projection.toPixels(gp1, point); // mode=1:start if(mode==1) { if(defaultColor==999) paint.setColor(Color.BLUE); else paint.setColor(defaultColor); RectF oval=new RectF(point.x - mRadius, point.y - mRadius, point.x + mRadius, point.y + mRadius); // start point canvas.drawOval(oval, paint); } // mode=2:path else if(mode==2) { if(defaultColor==999) paint.setColor(Color.RED); else paint.setColor(defaultColor); Point point2 = new Point(); projection.toPixels(gp2, point2); paint.setStrokeWidth(5); paint.setAlpha(120); canvas.drawLine(point.x, point.y, point2.x,point2.y, paint); } /* mode=3:end */ else if(mode==3) { /* the last path */ if(defaultColor==999) paint.setColor(Color.GREEN); else paint.setColor(defaultColor); Point point2 = new Point(); projection.toPixels(gp2, point2); paint.setStrokeWidth(5); paint.setAlpha(120); canvas.drawLine(point.x, point.y, point2.x,point2.y, paint); RectF oval=new RectF(point2.x - mRadius,point2.y - mRadius, point2.x + mRadius,point2.y + mRadius); /* end point */ paint.setAlpha(255); canvas.drawOval(oval, paint); } } return super.draw(canvas, mapView, shadow, when); } } |
3. How to use DrawPath(…) function in your activity.
3.1 Your activity must extends MapActivity, instead of Activity.
| Java: |
| ublic class RoutePath extends MapActivity { /** Called when the activity is first created. */ MapView mapView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); MapView mapView = (MapView) findViewById(R.id.myMapView1); double src_lat = 25.04202; // the testing source double src_long = 121.534761; double dest_lat = 25.05202; // the testing destination double dest_long = 121.554761; GeoPoint srcGeoPoint = new GeoPoint((int) (src_lat * 1E6), (int) (src_long * 1E6)); GeoPoint destGeoPoint = new GeoPoint((int) (dest_lat * 1E6), (int) (dest_long * 1E6)); DrawPath(srcGeoPoint, destGeoPoint, Color.GREEN, mapView); mapView.getController().animateTo(srcGeoPoint); mapView.getController().setZoom(15); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } private void DrawPath(GeoPoint src, GeoPoint dest, int color, MapView mMapView01) { // code in section 2.2 } } |
3.2 The screenshot
Emulator:
HTC G1: Actually, the driving direction is just one of the function of our project. Our project is so-called Dynamic ridesharing.
4. Trouble Shooting
When the program is executed, we can observe the logcat in Eclipse to see if the parsing procedure works properly or not. If there is no path shown on the map, you should check if the distance of source and destination is too long(e.g., from Taiwan to Japan). No routing path will be shown in this case.
To enable the logcat, please refer to:
http://csie-tw.blogspot.com/2009/05/enable-android-log-androidlog.html
5. Source code
Download here http://www.mediafire.com/?tlfshkkq58l38p1#
or http://webtoolplus.com/downloads/RoutePath.zip.
Please let me know if it's broken.
6. References
[1] Google Map Parameters:
http://mapki.com/index.php?title=Google_Map_Parameters
[2] Enable Android log:
http://csie-tw.blogspot.com/2009/05/enable-android-log-androidlog.html
[3] Setup the Android (Trad. Chinese):
http://csie-tw.blogspot.com/2008/01/androideclipse.html
[4] Android – Update current location by LocationProvider
http://csie-tw.blogspot.com/2009/09/android-update-current-location-by.html
Blogger Hack - How to add a Random Post Gadget in Blogger)




2009/6/29 下午9:43:00
This is very nice. I try your code, but I got an IOException when calling getInputStream from HttpURLConnection. Have you ran into this issue before?
2009/6/30 上午3:40:00
Hey, I guess the sth wrong in URL.
Use logcat to see the URL.
2009/6/30 上午5:53:00
So, I Log.d the URL to logcat. But when I copy and paste the URL from the logcat, it does ask you to open the KML file which means the URL is correct. do you have any idea?
2009/6/30 上午11:02:00
show me URL,please
2009/6/30 下午3:15:00
Hi Tommy, What I found out is if the kml file is over 40K. Then you will have the same issue. If I use exactly the same URL you used in your code, then it works.
2009/6/30 下午6:11:00
Hey guy,
please refer to section 4 for this issue. Thanks for the feedback.
By the way, r u a student?
2009/8/28 上午11:37:00
Hey, your tutorial is very good, but I want know if you know how can show info window of a position in a mapview into android.
answers to blopad14@gmail.com
thank you
2009/8/28 下午12:02:00
do u mean the longitude and latitude?
2009/9/3 下午2:49:00
I'll give you a hint:
the String in the Android environment is limited to 32 KiB of length. So, you better download it partially and store the relevant data into an ArrayList as this one stores the data in an ordered way. This one of the ways to get behind this limitation factor.
I came accross this limitation as I wrote an application with upload/download services. Though a byte [] for example can hold more than 32 KiB!
2009/9/11 下午4:06:00
hi tommy,
does your code can detect your "from" location dynamic?and update your route?
thanks
2009/9/12 上午1:35:00
Hi, there,
That is another story. Updating the latest location isn't a hard work.
I have spent lots of time writing a new article for you.
Check here:http://csie-tw.blogspot.com/2009/09/android-update-current-location-by.html
2009/10/25 上午4:57:00
Hi Tommy,
Thanks for the tutorial, i just wanted to find out that if u could post ur source file with us and wanted to find out if this tutorial will work under sdk 1.5
Thanks
RTN
2009/10/25 下午10:47:00
Don't Worry Tommy,
I have written the app using ur tutorial. I have modified ur tutorial to work with the GPS and it works fine on the phone. BUT after couple of minute my app frezes and it take long to drag around the map. Please let me know what is causing this problem.
2009/12/1 上午11:35:00
Very useful post, but can't get locations in Korea
Thank you very much. Excellent post.
2010/1/4 下午4:14:00
hi,
it seems that this KML approach will not work properly when the intermediary points contain highways, tollways etc. the KML file will only return the start point of the freeway and the location of the exit ramp.
there simply is not enough info to draw a path following the curves of the highway. i suspect a straight line will result instead. correct me if i m wrong...thanks for sharing the info though...
2010/1/4 下午5:48:00
sorry never mind. i missed the last part of the XML which contains all the points inside the tag.
2010/1/29 下午5:32:00
請問一下!
為什麼Android 1.1版後就不提供Driving Direction ?
原因為何您知道嗎?
2010/1/29 下午6:25:00
確切原因不曉得。
2010/2/19 上午12:29:00 作者已經移除這則留言。
2010/2/19 上午12:36:00
To l.d.stent,
Sorry. It's a typo. DrawPath(...) in section 2.2.
I have corrected it.
2010/3/15 上午11:13:00
thank you very much . it was too helpful for our final project.
2010/4/13 下午6:28:00
Why are you adding a new overlay for each line instead of drawing all the lines in one overlay?
2010/4/13 下午8:23:00
To Roel,
There are only two GeoPoint (i.e.) gp1, and gp2 in MyOverLay. Thus, MyOverLay can only presents a line instead of multi-lines.
2010/4/15 下午5:28:00
To csie-tw,
Thanks for your response, but why not have a collection of GeoPoints in your overlay and draw lines between them in a loop?
Are multiple overlays better for performance or is there no particular reason for it?
I noticed that the map's responsiveness gets worse when you have two points further away from each other, probably because it has to draw more lines. Is there a way to improve performance? For example only draw the route that is visible on screen instead of redrawing the whole route every time you scroll the map.
2010/5/2 上午1:43:00
So, I got the kml file coming in..and it shows my path, but it wont show my pairs at all...It gives me a error right at the pairs sections. Saying Arrayindexoutofbounds, I added another exception to handle it and it does. But my Log still wont get the the pairs part and print them out. Any suggestions?
2010/6/3 下午5:28:00
This isn't needed anymore:
http://googlegeodevelopers.blogspot.com/2010/05/directions-web-service-arrives-at.html
2010/6/8 下午1:19:00
Has anyone tried adding driving directions to an Android app using the Directions Web Service that Roel mentioned? It sounds nice, but I can't figure out how to add the overlay (then again I am very new to programming for Android). If anyone has a version of this tutorial using the new Driving Service that would be greatly appreciated!
Thanks.
2010/6/8 下午6:06:00
i think article is great, but I get Stringindexoutofboundexception on line : doc = db.parse(urlConnection.getInputStream());
Can anyone help, please? Thanks
2010/6/9 上午7:40:00
Hi, thanks for the code.
Running the app It only displays the path, but not the map! do u have any suggestion? I'm running on avd based on android 1.5.
2010/6/11 下午10:59:00
Hi domenico
Check permission configuration in Manifest file or Map API Key. (section 1.1 and 1.2)
2010/6/16 下午3:41:00
Hi, is there a way to get the distance of the route itself using this? Thanks for sharing.
2010/6/18 下午9:55:00
Hi green,
If the two points are represented as (Lat1r, Long1r) and (Lat2r, Long2r), the distance of two points is calculated by the following formula. It is noted that R is the radius of earth in kilometers. In addition, we assume the earth is a perfect sphere.
distance = acos(sin(Lat1r) * sin(Lat2r) + cos(Lat1r) * cos(Lat2r) * cos(Long2r - Long1r)) * R.
Finally, all you have to do is sum all of the distance between two points. The total distance is then obtained.
2010/6/21 上午9:44:00
sorry im not really good at this can i know where do i actually put this logic and the distance is actually following the route and not a straight line?
2010/6/23 上午10:37:00
erm let me actually all i want to know is how and where do i get all the points of the route
2010/6/25 下午10:15:00
Hi green,
The routing path is provided by google. All points in the path are shown in the KML file such as the example in section 2.1.
2010/6/28 下午12:09:00
Thanks i solved the problem thanks anyway :)
2010/11/20 下午8:55:00
請問如果是要規劃走路呢,因為出來是開車的
2011/3/10 下午4:19:00
Thanx for the tutorial, I have a problem , when I run this program, the map is display but I don't see any route.
Is there any one can help me?
2011/3/14 下午11:22:00
To it girl,
Did you dump the route paths by using logcat? Please check if the kml file containing the correct paths.
2011/3/21 下午8:54:00
TO csie-tw.blogspot.com
thnx a lot
the code is working and the route is display =)
but I have another problem ... immm when I trying to but the bubble Icon the Force Close message is display =(
Can u help me please.
thnx again.
2011/3/22 下午12:36:00
To it girl,
try to what?
2011/3/23 上午2:58:00
try to put pin in google map
that means when user click this pin the windows must display to describe this location.
Can u help me
thanks thanks so much
2011/3/27 下午7:40:00
To it girl,
What's the error message?
Did you use thread?
2011/3/28 上午3:29:00
To csie-tw.blogspot.com
The problem was resolved... ^_^
Thank you very much for every things
2011/4/15 上午2:46:00
How to use the draw () method? Where in the code is invoked?
2011/4/21 上午2:03:00
It is great tutorial. Thanks for that. But I have an important question. How can I clear the path that is drawned in here? I have written an application and i have to draw a new path but before it i must clear the old one. How can i do it according to that example??
2011/5/16 下午7:29:00
Hi. i want 2 display route more than 2 cities.
How can i display it..?
plz help me..
Thank u.
2011/5/31 下午6:56:00
Hi,
I'm able to get the map but not the route. So may I know where went wrong?
Or can I send you my code to you then you help me see where went wrong?
2011/9/4 上午2:40:00
That's a great tutorial and so much helpful...But i want to add two marker at the starting and ending point...how can i do that
2011/10/11 上午11:09:00
Firstly,thank you for this nice and helpful tutorial!!
@ shopno nill
I think you can use an ItemizedOverlay where you can "pin" a drawable on the map,on a specific geographical position.
But I have a question too.Views can be pinned on a specific geographical location on a map,what about a line??Is the line of this tutorial pinned on the map or if the map underneath is moved,the line will stay at the same position of the screen connecting two random,wrong locations??
2011/12/6 上午12:59:00
Thank you!
This post saved my life ;)
2012/3/20 上午11:52:00
Thank you!
2012/3/20 上午11:55:00
Hi!
Is there a way to calculate the route with walking directions? Or is it possible to ignore the driving directions?
I know the google directions api but i need a request without usage-limits...
Thanks
2012/3/20 下午11:38:00
Sorry. I have no idea about walking directions. Maybe there's parameter to determine the route type.
2012/7/9 下午1:58:00
Hey I was trying to build your project but setContentView(R.layout.activity_main);
at this point it is not able to recognise the path , I had also downloaded your source code in that I am not able to see any error but it is when I run the code it says error in xml and shows an exclamation mark on the project .
2012/7/9 下午11:03:00
@niteshnarayanlal,
Please try it on Android 2.3.
2012/7/28 上午4:12:00
It used to work greatly! But it cannot work in these days. It doesn't return the kml result even use your example link in the IE browser. Maybe Google changes something on its side? Any idea / solution? Thanks.
2012/8/4 下午3:48:00
yes Gary chen, same problem here, it worked fine till last month but now the kml file is not generating. Is there any other alternative anyone can suggest? badly in need of help!!!
2012/9/18 下午5:29:00
Hello,
I used this code but it does not show me the path, just brings me to this point of the map. What could be wrong?
2013/1/24 下午2:19:00
i tried this code but nothing comes up.only the blank map view