Android中Google地图路径导航,使用mapfragment地图上画出线路(google map api v2)详解

在这篇里我们只聊怎么在android中google map api v2地图上画出路径导航,用mapfragment而不是mapview,至于怎么去申请key,manifest.xml中加入的权限,系统中需要的google play services等另行查看资料,沦落凡间不详述。

参考:https://developers.google.com/maps/documentation/android/intro

首先我们在Activity上加载一个GoogleMap,然后再在Map上画上标记和路径导航。

先上主要代码:

 public class DirectionActivity extends FragmentActivity {
private Button btnBack;
private SupportMapFragment mapFragment;
private GoogleMap map;
private LocationManager locationManager;
private Location location;
private List<LatLng> latlngs = new ArrayList<LatLng>();
private double lat;
private double lng;
private String address;
private double locLat;
private double locLng;
private LatLng locLatLng; @Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
init();
findViewById();
setListenter();
processLogic();
getDirection();
} /**
* Get the direction
*/
private void getDirection() {
FoundRoadRouteTask task = new FoundRoadRouteTask(onFoundRoadRouteTaskListener);
task.execute(new String[] {locLat+","+locLng, lat + "," + lng });
} /**
* Draw route information
*/
private void drawRoute() {
try {
// Draw route info
map.addMarker(new MarkerOptions().position(latlngs.get(0)).title(address).visible(true));
PolylineOptions lineOptions = new PolylineOptions();
lineOptions.width(5);
for (int i = 0; i < latlngs.size() - 1; i++) {
lineOptions.add(latlngs.get(i));
}
map.addPolyline(lineOptions);
} catch (Exception e) { }
} private OnFounedRoadRouteListener onFoundRoadRouteTaskListener = new OnFounedRoadRouteListener() { @SuppressWarnings("unchecked")
@Override
public void found(Object obj) {
if (obj != null) {
List<LatLng> tempLats = (List<LatLng>) obj;
latlngs.addAll(tempLats);
}
drawRoute();
}
}; private void getLatLng() {
try {
Intent latlngIntent = getIntent();
Bundle b = latlngIntent.getBundleExtra("latlng");
lat = b.getDouble("lat");
lng = b.getDouble("lng");
address = b.getString("address");
} catch (Exception e) { }
} protected void init() {
setContentView(R.layout.direction_layout);
getLatLng();
btnBack = (Button) this.findViewById(R.direction_layout.btn_back);
} protected void processLogic() { locLat=application.getLatitude();
locLng=application.getLongitude(); FragmentManager manager = getSupportFragmentManager();
mapFragment = (SupportMapFragment) manager
.findFragmentById(R.direction_layout.map);
map = mapFragment.getMap();
initMap();
} protected void setListenter() {
btnBack.setOnClickListener(onBackClickListener);
} /**
* Initialize the map
*/
private void initMap() {
try {
//设置在地图上显示手机的位置,和显示控制按钮
map.setMyLocationEnabled(true);
//设置室内地图是否开启
map.setIndoorEnabled(true);
//设置地图类型三种:1:MAP_TYPE_NORMAL: Basic map with roads.
//2:MAP_TYPE_SATELLITE: Satellite view with roads.3:MAP_TYPE_TERRAIN: Terrain view without roads.
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
// map.setTrafficEnabled(true);
map.setOnMapLongClickListener(onMapLongClickListener); GPSUtil gpsUtil = new GPSUtil();
gpsUtil.startLocation(this, getContentResolver(),
onLocationChangedListener); locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (Exception e) { }
} /** On Location change listener */
private OnLocationChangedListener onLocationChangedListener = new OnLocationChangedListener() { @Override
public void onLocationChanged(Location location) {
// To get the local latitude and longitude and set the map view to
// the position
if (location != null) {
locLat = location.getLatitude();
locLng = location.getLongitude();
locLatLng = new LatLng(locLat, locLng);
map.moveCamera(CameraUpdateFactory.newLatLng(locLatLng));
map.moveCamera(CameraUpdateFactory.zoomTo(15));
}
}
}; /** On Map long click listener */
private OnMapLongClickListener onMapLongClickListener = new OnMapLongClickListener() { @Override
public void onMapLongClick(LatLng latlng) {
Location location = new Location("LongPressLocationProvider");
location.setLatitude(latlng.latitude);
location.setLongitude(latlng.longitude);
//设置精度
location.setAccuracy(20);
onLocationChangedListener.onLocationChanged(location);
}
}; private OnClickListener onBackClickListener = new OnClickListener() { @Override
public void onClick(View v) {
DirectionActivity.this.finish();
}
};
}

分析:

     private void getLatLng() {
try {
Intent latlngIntent = getIntent();
Bundle b = latlngIntent.getBundleExtra("latlng");
lat = b.getDouble("lat");
lng = b.getDouble("lng");
address = b.getString("address");
} catch (Exception e) {

}
}

在这个方法中我们从intent中拿到启动这个fragmentActivity时传过来的目的地经纬度。

     protected void processLogic() {

         locLat=application.getLatitude();
locLng=application.getLongitude(); FragmentManager manager = getSupportFragmentManager();
mapFragment = (SupportMapFragment) manager
.findFragmentById(R.direction_layout.map);
map = mapFragment.getMap();
initMap();
}

这里的3,4行为拿到当前本地的经纬度,application为一个Application类的对象,里面写有get方法,可以拿到当前本地经纬度。6,7行为得到mapFragment对象。9行为通过mapFragment获得GoogleMap对象,后面我们就是用这个map对象来画标记和线路。

     private void initMap() {
try {
//设置在地图上显示手机的位置,和显示控制按钮
map.setMyLocationEnabled(true);
//设置室内地图是否开启
map.setIndoorEnabled(true);
//设置地图类型三种:1:MAP_TYPE_NORMAL: Basic map with roads.
//2:MAP_TYPE_SATELLITE: Satellite view with roads.3:MAP_TYPE_TERRAIN: Terrain view without roads.
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
// map.setTrafficEnabled(true);
map.setOnMapLongClickListener(onMapLongClickListener); GPSUtil gpsUtil = new GPSUtil();
gpsUtil.startLocation(this, getContentResolver(),
onLocationChangedListener); locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (Exception e) {

}
}

这个方法用来初始化地图,3-11行为地图的设置,更多请查看:http://developer.android.com/reference/com/google/android/gms/maps/GoogleMap.html 。13-19行的GPSUtil为一个监听本地位置改变的类,当手机位置移动时GPS会得到移动后的经纬度。

     private OnLocationChangedListener onLocationChangedListener = new OnLocationChangedListener() {

         @Override
public void onLocationChanged(Location location) {
// To get the local latitude and longitude and set the map view to
// the position
if (location != null) {
locLat = location.getLatitude();
locLng = location.getLongitude();
locLatLng = new LatLng(locLat, locLng);
map.moveCamera(CameraUpdateFactory.newLatLng(locLatLng));
map.moveCamera(CameraUpdateFactory.zoomTo(15));
}
}
};

这个匿名类里的方法设置了当位置改变后地图上指示点和镜头的变化,拿到经纬度后用一个LatLng类的对象来存放,11,22行设置视角的移动,moveCamera方法传入的是一个CameraUpdate对象,该对象可用CameraUpdateFactory来生成,传入CameraUpdateFactory.newLatLng(locLatLng)移动到这个新的经纬度的位置,CameraUpdateFactory.zoomTo(15)设置移动后视角镜头大小。

     private void getDirection() {
FoundRoadRouteTask task = new FoundRoadRouteTask(onFoundRoadRouteTaskListener);
task.execute(new String[] {locLat+","+locLng, lat + "," + lng });
}

这个方法为启动一个异步线程处理向gooogle服务器请求路线规划,传入起点和目的地的经纬度。FoundRoadRouteTask继承了AsyncTask。等下讲请求的地址和处理方法。

     private OnFounedRoadRouteListener onFoundRoadRouteTaskListener = new OnFounedRoadRouteListener() {

         @SuppressWarnings("unchecked")
@Override
public void found(Object obj) {
if (obj != null) {
List<LatLng> tempLats = (List<LatLng>) obj;
latlngs.addAll(tempLats);
}
drawRoute();
}
};

从这个回调方法中得到处理好的LatLng对象,里面存放了用来画出线路的所有点的经纬度(把点连成线)。

     /**
* Draw route information
*/
private void drawRoute() {
try {
// Draw route info
map.addMarker(new MarkerOptions().position(latlngs.get(0)).title(address).visible(true));
PolylineOptions lineOptions = new PolylineOptions();
lineOptions.width(5);
for (int i = 0; i < latlngs.size() - 1; i++) {
lineOptions.add(latlngs.get(i));
}
map.addPolyline(lineOptions);
} catch (Exception e) {

}
}

这个方法就是画出线路的主要方法了,第7行在地图上标记出手机的当前位置,通过GoogleMap的addMarker方法,传入一个MarkerOptions类型的对象,该对象设置了标记的信息,如:.position(LatLng latlng)设置地点,.title(String address)设置标记显示的地点名称,.visible(boolean b)设置标记是否可见。我们可以在map上画线段[addPolyline(PolylineOptions options)],多边形[addPolygon(PolygonOptions options)],圆[addCircle(CircleOptions options)],图像[addGroundOverlay(GroundOverlayOptions options)]。传入的都是一个PolygonOptions类型的对象,该对象定义了你所画的图形,我们画线路导航所以用addPolyline(),并使用PolygonOptions.add(LatLng... points)方法添加多个点的坐标(7-12行),lineOptions.width(5);设置了所画线的宽度(自行调整数值),最后用GoogleMap对象的addPolyline()方法画出路线导航。

下面是请求和处理路线坐标经纬度的方法:

1:首先我们向这个地此发送http请求(这个应该没问题吧):http://maps.google.com/maps/api/directions/xml?origin=[lat],[lng]&destination=[lat],[lng]&sensor=false&mode=driving

地址中的origin=[lat],[lng]为起始地的纬度和经度,destination=[lat],[lng]为目的地的纬度和经度(用double类型的经纬度数据替换中括号),xml为设置返回的数据格式为xml格式,也可以写为json。mode=driving为设置出行模式了驾驶,还有步行等方式,详细可参考首段中的api文档地址。

2:处理http请求返回的字符串(String strResult),在<overview_polyline>标签中有编码的线路导航坐标点经纬度,且已经接近于平滑,方法如下:

 List<LatLng> points=new ArrayList<LatLng>(); 
if (-1 == strResult.indexOf("<status>OK</status>")){
return null;
} int pos = strResult.indexOf("<overview_polyline>");
pos = strResult.indexOf("<points>", pos + 1);
int pos2 = strResult.indexOf("</points>", pos);
strResult = strResult.substring(pos + 8, pos2); List<GeoPoint> geoPoints = decodePoly(strResult);
// Log.i("tag", "geoPoints:"+geoPoints.toString());
LatLng ll;
Log.i("tag", "geopoints.size:"+geoPoints.size());
for(Iterator<GeoPoint> gpit=geoPoints.iterator();gpit.hasNext();){
GeoPoint gp=gpit.next();
double latitude=gp.getLatitudeE6();
latitude=latitude/1000000;
// Log.i("tag", "latitude:"+latitude);
double longitude=gp.getLongitudeE6();
longitude=longitude/1000000;
// Log.i("tag", "longitude:"+longitude);
ll=new LatLng(latitude, longitude);
points.add(ll);
}
// Log.i("tag", "points:"+points.toString()); return points;
      /**
* Parses the returned lines of code of XML overview_polyline
*
* @return List<GeoPoint>
*/
private List<GeoPoint> decodePoly(String encoded) { List<GeoPoint> poly = new ArrayList<GeoPoint>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0; while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
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;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng; GeoPoint p = new GeoPoint((int) ((lat / 1E5) * 1E6),
(int) ((lng / 1E5) * 1E6));
poly.add(p);
} return poly;
}

这样返回的列表points中存放的点即为我们要用来画线路的坐标点了。

到此android用google map api v2画线路导航的方法就讲完了,沦落凡间 已使用没有问题,有疑问可以在下面提出来。

上一篇:Android画图之抗锯齿


下一篇:LinkButton和HyperLink的页面跳转用法