Как использовать Driving Directions и MapView на платформе Android
В этой статье приведу простой пример использования MapView и Driving Directions в своих приложениях. Достигнуть поставленной цели можно двумя способами:
Использовать приложение Maps.
Intent myIntent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(«http://maps.google.com/maps?
f=d&hl=ru&saddr=55.854722232222,37.476111121111&daddr=55.966666667667,37.400000001&ie=UTF8&om=0&output=kml»));
startActivity(myIntent);
Результат:
Этот способ не требует никаких усилий от программиста, но для его реализации потребуется вызов сторонней программы. Если это недопустимо, то можно прибегнуть к более трудозатратному делу, а именно написать весь код по получению Driving Directions самому. Итак, приступим.
Создадем приложение с вот такой компановкой:
<?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»
android:background=»#FFFFFF»>
<com.google.android.maps.MapView
android:id=»@+id/mapview»
android:layout_width=»fill_parent»
android:layout_height=»fill_parent»
android:layout_weight=»1″
android:apiKey=»Ваш apiKey»
android:clickable=»true»/>
<TextView
android:id=»@+id/TextView01″
android:layout_height=»wrap_content»
android:layout_width=»fill_parent»
android:text=»Driving directions»
android:textColor=»#000000″>
</TextView>
<ScrollView
android:id=»@+id/ScrollView01″
android:layout_width=»fill_parent»
android:layout_height=»fill_parent»
android:layout_weight=»2″>
<TextView
android:id=»@+id/route»
android:layout_width=»fill_parent»
android:layout_height=»fill_parent»
android:textColor=»#000000″>
</TextView>
</ScrollView>
</LinearLayout>
При создании проекта указать BuildTarget — GoogleApis
В манифесте в <application> добавить:
<uses-library android:name=»com.google.android.maps» />
А также разрешить доступ в интернет:
<uses-permission android:name=»android.permission.INTERNET» />
Чтобы получить информацию о пути между двумя точками нужно послать HTTP запрос по следующему адресу:
«http://maps.google.com/maps?f=d&hl=ru&saddr=55.854722232222,37.476111121111&daddr=55.966666667667,37.400000001&ie=UTF8&om=0&output=kml»
естественно вставив нужные координаты начальной и конечной точки.
В ответ мы получим файл maps.xml, в котором содержится вся необходимая нам информация и который мы будем парсить при помощи DOM.
String urlString = «http://maps.google.com/maps?f=d&hl=ru&saddr=»
+ srcLat + «,» + srcLon + «&daddr=» + dstLat + «,» + dstLon
+ «&ie=UTF8&0&om=0&output=kml»;
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());
} catch (Exception e) {
Log.e(«parse error», «parsing is not succesful»);
}
В полученном xml файле для каждого отрезка пути нам нужно найти следующие теги:
…
<Placemark>
<name>Направляйтесь на юго-запад по ул. Фестивальная в направлении ш. Ленинградское</name>
…
…
<Point>
<coordinates>37.475950,55.854890,0</coordinates>
</Point>
…
Они содержат описание отрезка пути и координаты его начала.
Потом получим координаты всех точек пути:
<GeometryCollection>
<LineString>
<coordinates>37.475950,55.854890,0.000000 37.474170,55.854420,0.000000 37.471360,55.853790,0.000000
…
</coordinates>
</LineString>
</GeometryCollection>
Полученную информацию каждый может использовать по своему вкусу. Далее полный листинг программы.
//**********************************
//Листинг DrivingDirectionsDemo.java
//**********************************
package com.evtgroup.dd;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
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 android.app.ProgressDialog;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
public class DrivingDirectionsDemo extends MapActivity {
private MapView mapView;
private MapController mc;
private String[] routeContent;
private ProgressDialog progressDialog;
private ArrayList<String> route = new ArrayList<String>();
private String[] distances;
private static final double SRC_LAT = 55.854722232222;
private static final double SRC_LON = 37.476111121111;
private static final double DST_LAT = 55.966666667667;
private static final double DST_LON = 37.400000001;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView)findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setEnabled(true);
mapView.setSatellite(false);
mapView.displayZoomControls(true);
mc = mapView.getController();
mc.setZoom(12);
GeoPoint srcPoint = new GeoPoint((int)(SRC_LAT*1E6), (int)(SRC_LON*1E6));
mc.animateTo(srcPoint);
ConnectionThread thread = new ConnectionThread(new ConnectionHandler());
thread.setState(SRC_LAT + "", SRC_LON + "", DST_LAT + "", DST_LON + "");
progressDialog = ProgressDialog.show(this, "", "Загрузка...", true);
thread.start();
}
// Поток для запроса данных
private class ConnectionThread extends Thread{
private Handler handler;
private String srcLat, srcLon, dstLat, dstLon;
// Конструктор потока
ConnectionThread(Handler h){
handler = h;
};
public void run(){
boolean res = getDirectionData(srcLat, srcLon, dstLat, dstLon);
Bundle b = new Bundle();
b.putBoolean("res", res);
Message msg = handler.obtainMessage();
msg.setData(b);
handler.sendMessage(msg);
}
public void setState(String slat, String slon, String dlat, String dlon){
srcLat = slat;
srcLon = slon;
dstLat = dlat;
dstLon = dlon;
}
}
private class ConnectionHandler extends Handler{
public void handleMessage(Message msg){
progressDialog.dismiss();
if (!msg.getData().getBoolean("res")){ //Данные не получены
((TextView)findViewById(R.id.route)).setText("Данные не получены!");
}else{
String[] lonLat = routeContent[0].split(",");
//Добавляем точки пути
GeoPoint gp1 = new GeoPoint((int)(Double.parseDouble(lonLat[1])*1E6),
(int)(Double.parseDouble(lonLat[0])*1E6));
GeoPoint gp2;
for (int i = 1; i < routeContent.length; i++) {
lonLat = routeContent[i].split(",");
gp2 = new GeoPoint((int)(Double.parseDouble(lonLat[1])*1E6),
(int)(Double.parseDouble(lonLat[0])*1E6));
mapView.getOverlays().add(new DirectionPathOverlay(gp1, gp2));
gp1 = gp2;
}
// Показываем driving directions
String str = "";
for (int i = 0; i < route.size()-1; i++){
str = str + (i+1) + ". " + route.get(i) + " - " + distances[i] + "\n";
}
str = str + (route.size()-1) + ". " + route.get(route.size()-1);
((TextView)findViewById(R.id.route)).setText(str);
}
}
}
private boolean getDirectionData(String srcLat, String srcLon, String dstLat, String dstLon) {
String urlString = "http://maps.google.com/maps?f=d&hl=ru&saddr="
+ srcLat + "," + srcLon + "&daddr=" + dstLat + "," + dstLon
+ "&ie=UTF8&0&om=0&output=kml";
Document doc = null;
HttpURLConnection urlConnection = null;
URL url = null;
String pathContent = "";
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());
} catch (Exception e) {
Log.e("parse error", "parsing is not succesful");
return false;
}
//Получаем массив строк с координатами пути
NodeList nl = doc.getElementsByTagName("LineString");
Node n = nl.item(0);
pathContent = n.getFirstChild().getFirstChild().getNodeValue();
routeContent = pathContent.split(" ");
//Получаем направления пути
nl = doc.getElementsByTagName("name");
for (int s = 1; s < nl.getLength()-1; s++){
Node rootNode = nl.item(s);
String r = rootNode.getFirstChild().getNodeValue();
route.add(r);
}
//Получаем координаты опорных точек направлений пути
ArrayList<String[]> coords = new ArrayList<String[]>();
nl = doc.getElementsByTagName("coordinates");
for (int s = 0; s < nl.getLength()-1; s++){
Node rootNode = nl.item(s);
String r = rootNode.getFirstChild().getNodeValue();
coords.add(r.split(","));
}
//Получаем расстояния между опорными точками в км
distances = new String[coords.size()-1];
for (int i = 0; i < coords.size()-1; i++){
Location locationA = new Location("point A");
locationA.setLatitude(Double.parseDouble(coords.get(i)[1]));
locationA.setLongitude(Double.parseDouble(coords.get(i)[0]));
Location locationB = new Location("point B");
locationB.setLatitude(Double.parseDouble(coords.get(i+1)[1]));
locationB.setLongitude(Double.parseDouble(coords.get(i+1)[0]));
String str = locationA.distanceTo(locationB)/1000+"";
//Оставляем 2 цифры после запятой
if (str.length() > str.indexOf(".") + 2){
str = str.substring(0, str.indexOf(".") + 2);
}
str = str + " km";
distances[i] = str;
}
return true;
}
@Override
protected boolean isRouteDisplayed() {
return true;
}
}
//**********************************
//Листинг DirectionPathOverlay.java
//**********************************
package com.evtgroup.dd;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
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 DirectionPathOverlay extends Overlay {
private GeoPoint gp1;
private GeoPoint gp2;
public DirectionPathOverlay(GeoPoint gp1, GeoPoint gp2) {
this.gp1 = gp1;
this.gp2 = gp2;
}
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);
paint.setColor(Color.RED);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(4);
canvas.drawLine((float)point.x, (float)point.y, (float)point2.x, (float)point2.y, paint);
}
return super.draw(canvas, mapView, shadow, when);
}
}
Результат: