Склад знаний
В данный момент я TeamLead небольшой команды Android разработчиков. В этом блоге я перевожу англоязычные статьи, пишу о своих наработках в различных областях
среда, 5 декабря 2012 г.
Android Google Maps Api v2. Урок 4. Строим маршрут на карте
Итак, продолжаем нашу серию спонтанных уроков, вызванных необходимостью переводить своё приложение на новый API
Сегодня мы разберемся, как получить маршрут и отобразить его на карте. Для этого обратимся к API Google Directions.
Получать маршрут мы будем грамотно, используя AsyncTask. Мы должны обратиться к Google Service Directions, передать координаты начальной и конечной точек и распарсить JSON ответ. Например вот такой: http://maps.google.com/maps/api/directions/json?origin=55.772851,37.586806&destination=55.415003,37.899904&sensor=false
При этом мы в ответе мы получаем шифрованную полилайн для каждого шага, я написал метод decodePolilyne. Можно конечно ограничиться начальными и конечными координатами шага, но полученный результат вас не устроит, проверено на себе.
Итак, пишем интерфейс для AsyncTask, сохраняем его в файл OnRouteCalcCompleted.java:
public interface OnRouteCalcCompleted <
void onRouteCalcBegin();
void onRouteCompleted( ArrayList route );
>
И саму AsyncTask RouteHandler.java:
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.util.Log;
/**
* Класс возвращает полилинию дороги, если указан mapView, отрисовывается на нём
* @author awacs
*
*/
public class RouteHandler extends AsyncTask < private final static String TAG = «RouteHandler»; /**
* Для точного интерполирования марштура
*/
public static final int FINE_ROUTE = 1;
/**
* Для грубого интерполирования маршрута
*/
public static final int COARSE_ROUTE = 2;
private final HttpClient client = new DefaultHttpClient();
private String content;
private boolean error = false;
private String error_msg = «»;
private ArrayList polyline;
private int accuracyRoute = 1;
private long distance;
private OnRouteCalcCompleted listener;
public RouteHandler( OnRouteCalcCompleted l ) <
this.listener = l;
>
public double getDistance() <
Log.d(TAG, «distance = » + distance + «m»);
return distance/1000;
>
public void calculateRoute( double latStart, double lonStart, double latEnd, double lonEnd, int accuracy ) <
this.accuracyRoute = accuracy; StringBuilder origin = new StringBuilder();origin.append( Double.toString(latStart));
origin.append(«,»);
origin.append( Double.toString(lonStart));
StringBuilder destination = new StringBuilder();
destination.append( Double.toString(latEnd));
destination.append(«,»);
destination.append( Double.toString(lonEnd));
List nameValuePairs = new ArrayList ();
nameValuePairs.add(new BasicNameValuePair(«origin», origin.toString()));
nameValuePairs.add(new BasicNameValuePair(«destination», destination.toString() ));
nameValuePairs.add(new BasicNameValuePair(«sensor», «false»));
String paramString = URLEncodedUtils.format(nameValuePairs, «utf-8»);
execute( «http://maps.google.com/maps/api/directions/json» + «?» + paramString );
>
public boolean isError() <
return error;
>
public String getErrorMsg() <
return error_msg;
>
@Override
protected String doInBackground(String. urls) < Log.d(TAG, «RouteHandler::doInBackground»);
try <
Log.v(TAG, urls[0]);
HttpPost httppost = new HttpPost(urls[0]);
ResponseHandler responseHandler = new BasicResponseHandler();
content = client.execute( httppost, responseHandler );
> catch (ClientProtocolException e) <
Log.d(TAG, «GetRouteHandler::ClientProtocolException»);
e.printStackTrace();
error = true;
cancel(true);
> catch (IOException e) <
Log.d(TAG, «GetRouteHandler::IOException»);
e.printStackTrace();
error = true;
cancel(true);
>
return content;
>
protected void onPostExecute(String content) <
if (error) <
error_msg = «Offline»;
> else <
try <
JSONObject response = new JSONObject(content);
String status = response.getString(«status»);
Log.v(TAG, content);
if( status.equalsIgnoreCase(«OK») ) <
polyline = new ArrayList ();
JSONArray routesArray = response.getJSONArray(«routes»);
JSONObject route = routesArray.getJSONObject(0);
// массив с информацией об отрезке маршрута
JSONArray legs = route.getJSONArray(«legs»);
JSONObject leg = legs.getJSONObject(0);
JSONObject distanceObj = leg.getJSONObject(«distance»);
distance = distanceObj.getLong(«value»);
JSONObject durationObj = leg.getJSONObject(«duration»);
// содержит куб выделения информационного окна для маршрута.
JSONObject bounds = route.getJSONObject(«bounds»);
JSONObject bounds_southwest = bounds.getJSONObject(«southwest»);
JSONObject bounds_northeast = bounds.getJSONObject(«northeast»);
double maxLat = bounds_northeast.getDouble(«lat»);
double maxLon = bounds_northeast.getDouble(«lng»);
double minLat = bounds_southwest.getDouble(«lat»);
double minLon = bounds_southwest.getDouble(«lng»);
JSONArray steps = leg.getJSONArray(«steps»);
for( int i=0; i
JSONObject step = steps.getJSONObject(i);
JSONObject start_location = step.getJSONObject(«start_location»);
JSONObject end_location = step.getJSONObject(«end_location»);
double latitudeStart = start_location.getDouble(«lat»);
double longitudeStart = start_location.getDouble(«lng»);
double latitudeEnd = end_location.getDouble(«lat»);
double longitudeEnd = end_location.getDouble(«lng»);
LatLng startGeoPoint = new LatLng(latitudeStart,longitudeStart);
LatLng endGeoPoint = new LatLng(latitudeEnd,longitudeEnd);
JSONObject polylineObject = step.getJSONObject(«polyline»);
if( accuracyRoute == FINE_ROUTE ) <
List points = decodePoly(polylineObject.getString(«points»));
Log.d(TAG, » » + points.size());
polyline.addAll(points);
> else <
polyline.add(startGeoPoint);
polyline.add(endGeoPoint);
>
>
> else if( status.equalsIgnoreCase(«NOT_FOUND»)) <
// по крайней мере для одной заданной точки (исходной точки, пункта назначения или путевой точки) геокодирование невозможно.
> else if( status.equalsIgnoreCase(«ZERO_RESULTS»)) <
// между исходной точкой и пунктом назначения не найдено ни одного маршрута.
> else if( status.equalsIgnoreCase(«MAX_WAYPOINTS_EXCEEDED»)) <
// в запросе задано слишком много waypoints. Максимальное количество waypoints равно 8 плюс исходная точка и пункт назначения. ( (Пользователи Google Maps Premier могут выполнять запросы с количеством путевых точек до 23.)
> else if( status.equalsIgnoreCase(«INVALID_REQUEST»)) <
// запрос недопустим
>else if( status.equalsIgnoreCase(«OVER_QUERY_LIMIT»)) <
// служба получила слишком много запросов от вашего приложения в разрешенный период времени.
>else if( status.equalsIgnoreCase(«REQUEST_DENIED»)) <
// служба Directions отклонила запрос вашего приложения.
>else if( status.equalsIgnoreCase(«UNKNOWN_ERROR»)) <
// обработка запроса маршрута невозможна из-за ошибки сервера. При повторной попытке запрос может быть успешно выполнен
>
> catch (JSONException e) <
e.printStackTrace();
>
>
listener.onRouteCompleted( polyline );
> // end postExecute
/**
* Декодирует полилинию из переданной гуглом строки
* @param encoded
* @return
*/
private List decodePoly(String encoded) <
List poly = new ArrayList ();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index
int b, shift = 0, result = 0;
do <
b = encoded.charAt(index++) — 63;
result |= (b & 0x1f)
shift += 5;
> while (b >= 0x20);
int dlat = ((result & 1) != 0 ?
(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do <
b = encoded.charAt(index++) — 63;
result |= (b & 0x1f)
shift += 5;
> while (b >= 0x20);
int dlng = ((result & 1) != 0 ?
(result >> 1) : (result >> 1));
lng += dlng;
LatLng p = new LatLng( lat/1E5, lng/1E5);
poly.add(p);
>
return poly;
> // end decodePoly
> // end class
Для использования этого таска в нашей активити, нужно имплементить OnRouteCalcCompleted, соответвенно в Activity добавятся методы:
// а заодно и удалить прогрессбар 🙂
>
Да, теперь добавляем например в инициализацию mMap из урока 3 код для вызова AsyncTask и компилируем готовое приложение.
private RouteHandler routeHandler;
private void setUpMapIfNeeded() <
if (mMap == null) <
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView)).getMap();
>
routeHandler = new RouteHandler( this );
routeHandler.calculateRoute(55.772935, 37.594272, 55.88459, 37.4263165, RouteHandler.FINE_ROUTE);
>
Код полной активити:
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import java.sql.Time;
import java.util.ArrayList;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
public class MainActivity extends FragmentActivity implements LocationSource, LocationListener, OnRouteCalcCompleted < private final static String TAG = «MainActivity»;
private OnLocationChangedListener mListener;
private LocationManager lManager;
private GoogleMap mMap;
private static double mLatitude;
private static double mLongitude;
private RouteHandler routeHandler;
@Override
protected void onCreate(Bundle savedInstanceState) <
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView)).getMap();
//mMap.setTrafficEnabled(true);
mMap.setMyLocationEnabled(true);
mMap.setOnMapLongClickListener(this);
lManager = (LocationManager) getSystemService(LOCATION_SERVICE);
lManager.requestLocationUpdates( lManager.getBestProvider(new Criteria(), true), 1, 1000, this);
setUpMapIfNeeded();
>
@Override
protected void onResume() <
super.onResume();
setUpMapIfNeeded();
if( lManager != null ) <
lManager.requestLocationUpdates(lManager.getBestProvider(new Criteria(), true), 1, 1000, this);
>
>
private void setUpMapIfNeeded() <
if (mMap == null) <
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView)).getMap();
>
routeHandler = new RouteHandler( this );
routeHandler.calculateRoute(55.772935, 37.594272, 55.88459, 37.4263165, AppSettings.FINE_ROUTE);
>
protected void onPause() <
if( lManager != null ) <
lManager.removeUpdates(this);
>
super.onPause();
>
@Override
public void onLocationChanged(Location location) <
if( mListener != null ) <
mListener.onLocationChanged( location );
>
>
@Override
public void activate(OnLocationChangedListener listener) <
mListener = listener;
>
@Override
public void deactivate() <
mListener = null;
>
@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
>
@Override
public void onRouteCalcBegin() <
// TODO Auto-generated method stub
>
Источник
Android: как рисовать маршруты Google maps API V2 из текущего местоположения в пункт назначения
Как нарисовать направление маршрута от текущего местоположения до места назначения, которое (широта и долгота), у меня есть код, как показано ниже:
Я хочу рисовать из текущего местоположения по сети провайдера или gps, а затем нарисовать маршрут по дороге к месту назначения.
Я использую Android Google apis V2.
Спасибо за помощь.
3 ответов
Это отлично работает для меня:
Это не мой код, Я взял его из отличного ответа в stackoverflow, но я не могу найти этот ответ сейчас, поэтому вот код:
добавьте этот класс в свой проект:
затем используйте этот класс для своих нужд.
Например, чтобы нарисовать направления:
на sourcePosition, destPosition от типа LatLng, и вы даете им нужные точки.
Я написал Здесь части из моего кода, которые я думаю может помочь, любой вопрос приветствуется.
использование решения dvrm класс GMapV2Direction, это хорошее решение, и оно все еще работает, но теперь вам нужно реализовать метод getDocument в новом потоке, чтобы разрешить сетевые подключения. Это пример для AsyncTask для этого метода, остальная часть класса такая же. Вы можете обработать его с помощью дескриптора или реализовать собственный обратный вызов интерфейса, чтобы получить xml-ответ Docmuent.
Это метод асинхронного обработчика для активность:
еще одна вещь, если значение длительности неверно, решение для него-изменить одну строку кода класса GMapV2Direction:
Источник