本Demo中所含功能
1:定位,显示当前位置
2:地图多覆盖物(地图描点,弹出该点的详细信息)
3:坐标地址互相换算
4:POI兴趣点检索
5:线路查询(步行,驾车,公交)
6:绘制线路(OpenGL和地图SDK绘制)
百度地图的api:http://lbsyun.baidu.com/
在上述所有的功能中,先完成如下工作:
1、在百度地图API控制台创建AK, 请参考:http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key
2、下载百度地图的SDK。下载链接:http://lbsyun.baidu.com/sdk/download
根据个人的需要下载相对应的sdk
3、将上面下载的sdk放到自己项目中的对应的Lib下 ,可参考链接:http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject
4、配置AndroidMainfest.xml文件:
- < uses-permission android:name ="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name ="android.permission.INTERNET" />
- <uses-permission android:name= "com.android.launcher.permission.READ_SETTINGS" />
- <uses-permission android:name ="android.permission.WAKE_LOCK" />
- <uses-permission android:name ="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name ="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name ="android.permission.GET_TASKS" />
- <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name ="android.permission.WRITE_SETTINGS" />
-
-
- <uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION" />
-
- <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION" />
-
- <uses-permission android:name ="android.permission.READ_PHONE_STATE" />
-
- <uses-permission android:name= "android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
- <uses-permission android:name= "android.permission.BAIDU_LOCATION_SERVICE" />
- <uses-permission android:name= "android.permission.ACCES_MOCK_LOCATION" />
- <uses-permission android:name ="android.permission.ACCESS_GPS" />
- <uses-permission android:name ="android.permission.BROADCAST_STICKY" />
-
- <uses-permission android:name= "android.permission.PROCESS_OUTGOING_CALLS" />
- <uses-permission android:name= "android.permission.MODIFY_AUDIO_SETTINGS" />
- <uses-permission android:name ="android.permission.RECORD_AUDIO" />
-
- <uses-permission android:name ="android.permission.CAMERA" />
注:上面的权限是我的项目中所有用到的权限,具体可参考百度地图和定位地图所需要的权限。
基础地图参考: http://lbsyun.baidu.com/index.php?title=androidsdk/guide/hellobaidumap
定位参考: http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/buildprojec
还需要配置地图的AK以及定位service:
- < meta-data
- android:name= "com.baidu.lbsapi.API_KEY"
- android:value= "API控制台申请到的AK" />
-
- ; service
- android:name= "com.baidu.location.f"
- android:enabled= "true"
- android:process= ":remote" >
- </service >
5、在Application中初始化地图SDK
SDKInitializer.
initialize
(getApplicationContext());
1、定位并且显示当前位置
步骤:1、初始化LocationClient 类 ,并设置定位回调类(通过registerLocationListener()方法)
2、设置定位参数
3、发起定位
4、在回调接口中获取定位的信息
代码如下:
- import com.baidu.location.BDLocation;
- import com.baidu.location.BDLocationListener;
- import com.baidu.location.LocationClient;
- import com.baidu.location.LocationClientOption;
- import com.baidu.location.LocationClientOption.LocationMode;
- import com.lb.baidumapdemo.db.DBConstants;
- import com.lb.baidumapdemo.db.ShareDB;
- import com.lb.baidumapdemo.face.LocationFace;
-
- import android.content.Context;
-
-
-
-
-
-
-
-
- public class LocationFaceUtil implements BDLocationListener {
- private LocationFace locationFace;
- public LocationClient mLocationClient = null;
- private Context context;
-
- public LocationFaceUtil(Context context, LocationFace locationFace) {
- super();
- this. locationFace = locationFace;
- this. context = context;
- mLocationClient = new LocationClient(context);
- mLocationClient.registerLocationListener(LocationFaceUtil. this);
- startLocation();
- }
-
- private void startLocation() {
- LocationClientOption option = new LocationClientOption();
- option.setLocationMode(LocationMode. Hight_Accuracy);
- option.setCoorType( "bd09ll");
- option.setScanSpan(0);
- option.setIsNeedAddress( true);
- option.setOpenGps( true);
- option.setLocationNotify( true);
- option.setIsNeedLocationDescribe( true);
- option.setIsNeedLocationPoiList( true);
- option.setIgnoreKillProcess( false);
- option.SetIgnoreCacheException( false);
- option.setEnableSimulateGps( false);
- mLocationClient.setLocOption(option);
- mLocationClient.start();
- }
-
- @Override
- public void onReceiveLocation(BDLocation arg0) {
-
- if (arg0.getLocType() == 61 || arg0.getLocType() == 161 && arg0.getLatitude() != 0.0) {
-
- new ShareDB( context).save(DBConstants. CITY_NAME, arg0.getCity());
-
- locationFace.locationResult(arg0);
- }
- }
-
- }
在调用这个类的时候,我们只需要
- new LocationFaceUtil(getApplicationContext(), new LocationFace() {
-
- @Override
- public void locationResult(BDLocation location) {
- bdLocation = location;
- addMarker();
- }
- });
然后回调的信息就全部在这个bdLocation里面了,接着标注当前自己的位置,就是调用的
addMarker()方法
下面代码中的:mBaiduMap=
(MapView) findViewById(R.id.
basemap
)
.getMap();
- private void addMarker() {
-
- mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL);
-
- mBaiduMap.setTrafficEnabled( true);
-
- MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(19);
- mBaiduMap.setMapStatus(statusUpdate);
-
- LatLng latLng = new LatLng( bdLocation.getLatitude(), bdLocation.getLongitude());
-
- BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.drawable. icon_gcoding);
- OverlayOptions option = new MarkerOptions().position(latLng).icon(descriptor).draggable(true);
-
- mBaiduMap.clear();
-
- mBaiduMap.addOverlay(option);
-
- MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng);
-
- mBaiduMap.animateMapStatus(u);
- mBaiduMap.setOnMarkerClickListener(BaseMapActivity. this);
- mBaiduMap.setOnMarkerDragListener(BaseMapActivity. this);
- }
OK,到这里定位显示当前自己的位置的功能就已经完成了
2:地图多覆盖物(地图描点,弹出该点的详细信息)
首先,我构建了四个经纬度的点(实际中需要通过POI检索得到),然后循环将这些点添加到地图界面上,并给这些点设置额外的数据。 最后给覆盖物设置点击事件,在点击事件中弹出弹框
代码如下:
- import android.graphics.Point;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.TextView;
- import android.widget.Toast;
-
- import com.baidu.mapapi.map.BaiduMap;
- import com.baidu.mapapi.map.BaiduMap.OnMapClickListener;
- import com.baidu.mapapi.map.BaiduMap.OnMarkerClickListener;
- import com.baidu.mapapi.map.BitmapDescriptor;
- import com.baidu.mapapi.map.BitmapDescriptorFactory;
- import com.baidu.mapapi.map.InfoWindow;
- import com.baidu.mapapi.map.MapPoi;
- import com.baidu.mapapi.map.MapStatusUpdate;
- import com.baidu.mapapi.map.MapStatusUpdateFactory;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.mapapi.map.Marker;
- import com.baidu.mapapi.map.MarkerOptions;
- import com.baidu.mapapi.map.OverlayOptions;
- import com.baidu.mapapi.model.LatLng;
- import com.lb.baidumapdemo.R;
- import com.lb.baidumapdemo.base.BaseActivity;
-
- public class MarkerMapActivity extends BaseActivity implements OnMarkerClickListener,OnMapClickListener {
- private MapView mBaiduMapView;
- private BaiduMap mBaiduMap;
- private String[] titles = new String[] { "one", "two", "three", "four" };
-
- private LatLng[] latlngs = new LatLng[] { new LatLng(22.539895,114.058935), new LatLng(22.540729,114.066337),
- new LatLng(22.543763,114.06458), new LatLng(22.538614,114.062811) };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout. activity_markermap);
- mBaiduMapView = (MapView) findViewById(R.id. markermap);
- mBaiduMap = mBaiduMapView.getMap();
-
- mBaiduMap.setOnMapClickListener( this);
- initMarker();
- }
-
- private void initMarker() {
- mBaiduMap.clear();
- LatLng latLng = null;
- OverlayOptions overlayOptions = null;
-
- mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL);
-
- mBaiduMap.setTrafficEnabled( true);
- MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(17);
- mBaiduMap.setMapStatus(statusUpdate);
- BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.drawable. icon_gcoding);
-
- for ( int i = 0; i < titles. length; i++) {
- latLng= latlngs[i];
- overlayOptions = new MarkerOptions().position(latLng).icon(descriptor);
-
- Marker marker=(Marker) mBaiduMap.addOverlay(overlayOptions);
- Bundle bundle = new Bundle();
- bundle.putString( "info", titles[i]+ "个");
- marker.setExtraInfo(bundle);
- }
-
- MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng);
- mBaiduMap.setMapStatus(u);
-
- mBaiduMap.setOnMarkerClickListener(MarkerMapActivity. this);
-
- }
-
-
-
-
-
-
-
- @Override
- public boolean onMarkerClick(Marker marker) {
- final String msg = marker.getExtraInfo().getString( "info");
- InfoWindow mInfoWindow;
-
- TextView location = new TextView(getApplicationContext());
- location.setBackgroundResource(R.drawable. shape_popup);
- location.setPadding(30, 20, 30, 20);
- location.setText(msg);
-
- final LatLng ll = marker.getPosition();
- Point p = mBaiduMap.getProjection().toScreenLocation(ll);
- p. y -= 47;
- LatLng llInfo = mBaiduMap.getProjection().fromScreenLocation(p);
-
- mInfoWindow = new InfoWindow(location, llInfo, -47);
-
- mBaiduMap.showInfoWindow(mInfoWindow);
-
- location.setOnClickListener( new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Toast. makeText(MarkerMapActivity.this, msg, Toast.LENGTH_SHORT).show();
- }
- });
- return true;
- }
-
-
-
-
-
-
- @Override
- public void onMapClick(LatLng arg0) {
- mBaiduMap.hideInfoWindow();
-
- }
-
-
-
-
-
-
-
- @Override
- public boolean onMapPoiClick(MapPoi arg0) {
- return false;
- }
-
- }
3:坐标地址互相换算
在很多请求当中只会返回经纬度的坐标,并不会返回具体的信息,这个时候需要用到坐标换算成地址。
坐标反转类:GeoCoder类,我们可以看一下这个类的方法:
根据上图的方法说明,其实我们需要做的就明白了
第一步:初始化GeoCoder类(调用newInstance())
第二步:设置查询结果监听
第三步:发起请求
实际核心代码:
- private GeoCoder geoCoder;
- geoCoder = GeoCoder. newInstance();
- geoCoder.setOnGetGeoCodeResultListener( this);
- geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(arg0.getPosition()));
这里是根据经纬度来获取地址信息
然后在下面的方法里面回调:
-
-
-
-
-
- @Override
- public void onGetGeoCodeResult(GeoCodeResult arg0) {
-
- }
-
-
-
-
-
-
- @Override
- public void onGetReverseGeoCodeResult(ReverseGeoCodeResult arg0) {
-
- }
4:POI兴趣点检索
1、初始化PoiSearch类,构造检索的参数
检索,可以分为四种类型的检索,根据我们自己不同的需求,需要调用不同的方法,并传入不同的参数
这里我们先看一下范围内检索:
searchInBound
( PoiBoundSearchOption
option)
PoiBoundSearchOption类,他有四个方法,入下图所示,这里的pageNum是从0开始的!
在设置pageCapacity的时候,我在测试的过程中最大是50条,超过50默认就返回了10条(这个版本的是50),其他的参数就不多说了。
其他的三个检索的方法,和这个大同小异,想要详细的了解可以参考:http://wiki.lbsyun.baidu.com/cms/androidsdk/doc/v3_7_0/
2、设置Search回调接口
3、发起搜索
核心代码如下:
- private PoiSearch mSearch ;
- private int pageNum = 0;
- private void startPointSearch () {
- mSearch = PoiSearch.newInstance();
- mSearch.setOnGetPoiSearchResultListener(this);
- PoiNearbySearchOption option = new PoiNearbySearchOption();
- option.location( new LatLng( mLocation.getLatitude(), mLocation.getLongitude()));
- option.pageCapacity(50);
- option.pageNum( pageNum);
- option.radius(30000);
- option.sortType(PoiSortType. distance_from_near_to_far);
- option.keyword( "美食");
- mSearch.searchNearby(option);
- pageNum++;
- }
-
- @Override
- public void onGetPoiDetailResult(PoiDetailResult arg0) {
-
- }
-
-
- @Override
- public void onGetPoiResult(PoiResult arg0) {
-
-
- }
上面的代码中,onGetPoiResult(PoiResult arg0)方法中的PoiResult所携带的方法如下:所以可以根据我们自己不同的需求来进行得到信息进行处理。
比如:通过getAllPoi方法,可以得到
5:线路查询(步行,驾车,公交)
根据4我们可以得到两个POI兴趣点,然后我们就可以查询这两个点的线路
线路查询的关键类:
RoutePlanSearch
从上述api中我们可以看到,线路规划分为四条线路(以前没有发起骑行规划线路) ,在上面的四个发起线路的方法中,都需要传入一个参数,这里我就只讲解一下
transitSearch
( TransitRoutePlanOption
option)
这里面需要传入一个TransitRouterPlanOption对象,我们来看一下这个对象所有的方法:
然后我们看到,最重要的就是这个类:PlanNode这个类,这个类不仅在
TransitRouterPlanOption的方法中需要用到,在骑行线路、驾车线路、步行线路的方法中所需的对象中也都是需要设置PlanNode。
PlanNode解释:
路径规划中的出行节点信息,出行节点包括:起点,终点,途经点,
出行节点信息可以通过两种方式确定:
1: 给定出行节点经纬度坐标
2: 给定出行节点地名和城市名
so,我们可以根据自己的具体实际需求来设置这些参数:
看完API的解释之后,调用方法:
1、初始化RouterPlanSearch类,并设置回调接口
2、设置线路参数信息,发起线路查询
下面的代码,是通过地点信息来进行线路查询:
- private void startRouterResult( int type, String startAddr, String endAddr) {
- String cityName = new ShareDB(SearchInfoActivity.this ).getValue(DBConstants. CITY_NAME);
- PlanNode stNode = PlanNode.withCityNameAndPlaceName(cityName, startAddr);
- PlanNode enNode = PlanNode.withCityNameAndPlaceName(cityName, endAddr);
- if (type == 1) {
- routeSearch .transitSearch(new TransitRoutePlanOption().from(stNode).to(enNode).city(cityName));
- } else if (type == 2) {
- routeSearch .drivingSearch(new DrivingRoutePlanOption().from(stNode).to(enNode));
- } else if (type == 3) {
- routeSearch .walkingSearch(new WalkingRoutePlanOption().from(stNode).to(enNode));
- }
下面的代码是用过经纬度来进行线路查询的:
- private void startRouterResult( final int type, LatLng beLat, LatLng endLat) {
-
-
-
-
- if ( beLat != null && endLat != null) {
- String cityName = new ShareDB(SearchInfoActivity.this ).getValue(DBConstants. CITY_NAME);
- PlanNode stNode = PlanNode. withLocation(beLat );
- PlanNode enNode = PlanNode. withLocation(endLat);
- if (type == 1) {
- routeSearch.transitSearch( new TransitRoutePlanOption().from(stNode).to(enNode).city(cityName));
- } else if (type == 2) {
- routeSearch.drivingSearch( new DrivingRoutePlanOption().from(stNode).to(enNode));
- } else if (type == 3) {
- routeSearch.walkingSearch( new WalkingRoutePlanOption().from(stNode).to(enNode));
- }
- }
OK,下面就是获取结果的代码了:
-
-
-
-
- @Override
- public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult) {
- closeDialog();
- if (drivingRouteResult. error.toString().equals( "NO_ERROR")) {
- BaseApplication. drivingRouteResult = drivingRouteResult;
- startIntent(2);
- } else {
- Toast. makeText(SearchInfoActivity. this, "未找到路线,请重新选择起点或者终点" , Toast. LENGTH_SHORT).show();
- }
-
-
- @Override
- public void onGetTransitRouteResult(TransitRouteResult transitRouteResult) {
- closeDialog();
- if (transitRouteResult. error.toString().equals( "NO_ERROR")) {
- BaseApplication. transitRouteResult = transitRouteResult;
- startIntent(1);
- } else {
- Toast. makeText(SearchInfoActivity. this, "未找到路线,请重新选择起点或者终点" , Toast. LENGTH_SHORT).show();
- }
-
-
- @Override
- public void onGetWalkingRouteResult(WalkingRouteResult walkingRouteResult) {
- closeDialog();
- if (walkingRouteResult. error.toString().equals( "NO_ERROR")) {
- BaseApplication. walkingRouteResult = walkingRouteResult;
- startIntent(3);
- } else {
- Toast. makeText(SearchInfoActivity. this, "未找到路线,请重新选择起点或者终点" , Toast. LENGTH_SHORT).show();
- }
线路规划就到这里结束了,接着就是线路的绘制了。
6:绘制线路(OpenGL和地图SDK绘制)
步骤:1、得到经纬度集合,从5中线路查询中得到的结果,比如
WalkingRouteResult.
getRouteLines() 会返回一个
List<WalkingRouteLine>集合。将这个集合强行转为父类集合List<RouterLine>
2、得到List<RouterLine> 之后,得到其中一个RouterLine对象(就是其中一条线路),调用RouterLine
.getAllStep().get(i).
getWayPoints();
其中i为线路中的某一段线路,如果需要全部绘制完成,则循环i取出所有的WayPoints()即可
3、getWayPoint()返回的是
List
<LatLng>集合,根据经纬度集合,我们就可以开始绘制线路了
4、绘制线路
- List<LatLng> listLat = (List<LatLng>) getIntent().getSerializableExtra( "latlng" );
-
- mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL);
-
- mBaiduMap.setTrafficEnabled( true);
- MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(19);
- mBaiduMap.setMapStatus(statusUpdate);
- MyLatLng myLatLng = listLat.get(0);
- MapStatusUpdate u = MapStatusUpdateFactory. newLatLng( new LatLng(myLatLng.getLatitude(), myLatLng.getLongitude()));
- mBaiduMap.setMapStatus(u);
绘制线路的两种办法:
1、OpenGL绘制,代码如下:
- mBaiduMap .setOnMapDrawFrameCallback(callback );
- *************** 使用OpenGl绘制,是出现Bug,坐标的转换和屏幕上的点的转换,会随着地图大小的拉伸,OpenGl的线不拉伸的情况,建议不要使用此方法 *********************/
-
- OnMapDrawFrameCallback callback = new OnMapDrawFrameCallback() {
- public void onMapDrawFrame(GL10 gl, MapStatus drawingMapStatus) {
- if ( mBaiduMap.getProjection() != null) {
-
- calPolylinePoint(drawingMapStatus);
-
- drawPolyline(gl, Color. argb(255, 255, 0, 0), vertexBuffer, 10, 3, drawingMapStatus);
- }
- }
- };
-
-
- public void calPolylinePoint(MapStatus mspStatus) {
- PointF[] polyPoints = new PointF[ listLat.size()];
- vertexs = new float[3 * listLat.size()];
- int i = 0;
- for (MyLatLng xy : listLat) {
-
- polyPoints[i] = mBaiduMap.getProjection().toOpenGLLocation( new LatLng(xy.getLatitude(), xy.getLongitude()), mspStatus);
- vertexs[i * 3] = polyPoints[i]. x;
- vertexs[i * 3 + 1] = polyPoints[i]. y;
- vertexs[i * 3 + 2] = 0.0f;
- i++;
- }
- vertexBuffer = makeFloatBuffer( vertexs);
- }
-
-
- private FloatBuffer makeFloatBuffer( float[] fs) {
- ByteBuffer bb = ByteBuffer. allocateDirect(fs. length * 4);
- bb.order(ByteOrder. nativeOrder());
- FloatBuffer fb = bb.asFloatBuffer();
- fb.put(fs);
- fb.position(0);
- return fb;
- }
-
-
- private void drawPolyline(GL10 gl, int color, FloatBuffer lineVertexBuffer, float lineWidth, int pointSize, MapStatus drawingMapStatus) {
-
- gl.glEnable(GL10. GL_BLEND);
- gl.glEnableClientState(GL10. GL_VERTEX_ARRAY);
-
- gl.glBlendFunc(GL10. GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
-
- float colorA = Color. alpha(color) / 255f;
- float colorR = Color. red(color) / 255f;
- float colorG = Color. green(color) / 255f;
- float colorB = Color. blue(color) / 255f;
-
- gl.glVertexPointer(3, GL10. GL_FLOAT, 0, lineVertexBuffer);
- gl.glColor4f(colorR, colorG, colorB, colorA);
- gl.glLineWidth(lineWidth);
- gl.glDrawArrays(GL10. GL_LINE_STRIP, 0, pointSize);
-
- gl.glDisable(GL10. GL_BLEND);
- gl.glDisableClientState(GL10. GL_VERTEX_ARRAY);
- }
2、利用SDK绘制点、线、多边形
-
-
-
-
- OverlayOptions polygonOption = new PolylineOptions().points(listLat ).color(Color.parseColor( "#FF0000")).width(7);
-
- mBaiduMap.addOverlay(polygonOption);
这个百度地图的集成的时间大概是2015年9月,所以SDK和最新的肯定多多少少有点差异的。
GitHub下载地址(AndroidStudio):http://download.csdn.net/detail/q908555281/9472070
CSDN下载地址(Eclipse): http://download.csdn.net/detail/q908555281/9472070
本Demo用的百度的Key为私人的,如果要正常运行,得自己去百度地图控制台申请Key,来替换Mainfest中的key