关于百度地图的简单开发前段时间,写过一个小系列的博客关于百度地图的基本地图,定位,全景,导航等功能做了简单的介绍.从今天开始又将准备一期有关百度地图的POI检索的等一列查询功能,如城市检索,周边检索,区域检索;公交地铁查询;线路规划检索等.今天首先来第一波就是基于百度地图的API实现公交地铁线路查询.那么就开始这次再续前缘之第一篇公交地铁线路查询.
公交地铁线路查询可以说在生活当中非常的实用,乃至更高级一点的实时公交查询,使得人们的生活出行变得更加方便快捷.实际上实现公交地铁线路的查询比较简单.原理上也是非常清晰的.但是必须先明白一个知识就是POI,什么是POI英文名称是Point of Interest,即兴趣点.这个具体有什么作用了.可以说百度地图中的很多功能的数据都来自它;比如周边搜索,地点搜索,线路搜索,公交地铁查询,周边雷达等功能.POI个人理解就是在地理信息系统的一个关键点,它可以是一栋房子,一棵树,一个公交站台等.而POI实际上有个库,里面有许许多多不同类型的POI点的信息数据,而POI检索就类似百度搜索中关键字搜索,输入某个关键字,然后就返回一连串与之相关数据信息.所以也很明白这个POI库并不是哪家公司就能建立的,但是百度和Google可以,别忘了他们可是搜索引擎中的老大,以至于建立这个庞大的POI库相对其他公司有着特别优势.POI中传入一些关键字,就会返回一些与之相关的poi点对象,该对象中封装了相应点数据信息.然后我们就会在这些不同类型的POI中去筛选我们所需要的poi即可.
实现的大致思路:
通过上面的有关POI一些介绍,相信对POI有了一个初步认识.有了初步认识就可以.思路就是创建一个POISearch对象,用于发起POI检索请求,请求中传入相关的关键字作为请求参数,然后给该对象设置一个OnGetPoiSearchResultListener(POI检索结果监听器)主要是用于返回监听到的POI数据信息,如果有POI数据返回就会在监听事件中产生一个回调返回检索到的结果.实际上到了这一步就类似上面所说的返回一些相关不同类型的POI,然后通过筛选,得到BusLine(公交线路类型的POI和地铁类型的POI),然后这些poi中会携带一个uid(这个很关键呀),只要拿到线路的uid就已经成功一半了,然后再去创建一个BusLineSearch对象,用于查询公交和地铁线路信息,并传入上面的得到的uid,并且也需要给该对象设置一个OnGetBusLineSearchResultListener公交信息查询结果监听器,主要用于检索公交地铁线路信息,如果检索成功会通过回调方法返回检索的结果.拿到返回的结果就可以创建一个BuslineOverlay,用于显示公交线路或地铁线路的图层.
一,创建PoiSearch对象并给该对象设置OnGetPoiSearchResultListener监听器:
poiSearch=PoiSearch.newInstance();//创建POI兴趣点检索对象poiSearch.setOnGetPoiSearchResultListener(poiSearchResultListener);//并且给该对象设置监听器,如果有结果返回就立即触发该回调方法返回兴趣点的uid集合
/*** POI检索结果监听器*/OnGetPoiSearchResultListener poiSearchResultListener =new OnGetPoiSearchResultListener() {@Overridepublic void onGetPoiResult(PoiResult poiResult) {if (poiResult == null|| poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {// 没有找到检索结果Toast.makeText(BusSearchActivity.this, "未找到结果",Toast.LENGTH_LONG).show();return;}if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {// 检索到结果正常返回// 遍历所有poi,找到类型为公交线路的poibusLineUidList.clear();//先清空一下该uid集合,因为可能留有上一次中的数据for (PoiInfo poi : poiResult.getAllPoi()) {//遍历返回的所有的poi,这其中的poi有很多类型,很多数据就好比关键字搜索返回多种多样数据结果一样,并且返回的POI中还会带有一个uid,if (poi.type == PoiInfo.POITYPE.BUS_LINE|| poi.type == PoiInfo.POITYPE.SUBWAY_LINE) {//先在众多类型的数据中,筛选出公交线路类型,地铁线路类型busLineUidList.add(poi.uid);//然后在到筛选得到的poi中取出uid,并加入到公交线路集合中去}}searchBusline();}}
二,创建BusLineSearch对象并给该对象设置OnGetBusLineSearchResultListener监听器:
/*** 公交信息查询结果监听器*/OnGetBusLineSearchResultListener busLineSearchResultListener=new OnGetBusLineSearchResultListener() {@Overridepublic void onGetBusLineResult(BusLineResult busLineResult) {if (busLineResult.error == SearchResult.ERRORNO.NO_ERROR) {//表示得到结果类型是NO_ERROR,没有错误,就说明返回了公交线路的信息rLayout.setVisibility(View.VISIBLE);myBaiduMap.clear();BusLineOverlay overlay = new MyBuslineOverlay(myBaiduMap);// 用于显示一条公交详情结果的Overlay,定义一个公交线路的图层用于显示公交线路overlay.setData(busLineResult);overlay.addToMap();// 将overlay添加到地图上overlay.zoomToSpan();// 缩放地图,使所有overlay都在合适的视野范围内myBaiduMap.setOnMarkerClickListener(overlay);// 公交线路名称stations=busLineResult.getStations();//通过getStations方法可以得到该条公交线路中途径的所有的站台/*for (int i=0;i<stations.size();i++) {toast("第"+(i+1)+"站: "+stations.get(i).getTitle());}toast("线路:"+busLineResult.getBusLineName()+" 首班车时间:"+busLineResult.getStartTime()+" 末班车时间:"+busLineResult.getEndTime());*/} else {//否则提示未找到结果Toast.makeText(BusSearchActivity.this, "抱歉,未找到结果",Toast.LENGTH_SHORT).show();}}};
三,搜索公交地铁线路方法:(注意:这里有个cityName是前面通过定位得到的城市名,也就是说自动默认为你查询你所处的城市的公交路线)
/*** @author mikyou* 搜索公交线路* */private void searchBusline() {if (buslineIndex >= busLineUidList.size()) {//表示上一次的数据buslineIndex没有清空,所以就对buslineIndex进行初始化buslineIndex = 0;}if (buslineIndex >= 0 && buslineIndex < busLineUidList.size()&& busLineUidList.size() > 0) {//下面表示如果检索到了相应的公交线路,就返回true,否则返回false;这里的cityName就是传入的城市名,//cityName是通过MainActivity中的定位得到城市,所以也就实现了默认查询你所处城市的公交路线,//uid就传入通过poiSearch检索到的兴趣点中并筛选出的公交或地铁类型的uid,然后就通过OnGetBusLineSearchResultListener监听器//如果监听有公交线路信息,就返回一个true boolean flag = busLineSearch.searchBusLine((new BusLineSearchOption().city(cityName).uid(busLineUidList.get(buslineIndex))));if (flag) {Toast.makeText(BusSearchActivity.this, "检索成功~", 1000).show();} else {Toast.makeText(BusSearchActivity.this, "检索失败~", 1000).show();}buslineIndex++;}}
布局文件:
<LinearLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FFF"android:padding="10dp" ><ImageViewandroid:id="@+id/search_back"android:layout_width="20dp"android:layout_height="20dp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:scaleType="center"android:src="@drawable/search_back" /><EditTextandroid:id="@+id/search_content"android:layout_width="220dp"android:layout_height="40dp"android:layout_centerVertical="true"android:layout_marginLeft="10dp"android:layout_toRightOf="@+id/search_back"android:background="@drawable/edit_bg"android:drawableLeft="@drawable/search2"android:drawablePadding="5dp"android:hint="搜地铁、搜公交"android:textSize="16sp"android:textColor="#bbcccccc"android:textColorHint="#aacccccc"android:padding="10dp" /><Buttonandroid:id="@+id/ok_btn"android:layout_width="wrap_content"android:layout_height="40dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginLeft="10dp"android:layout_marginRight="5dp"android:layout_toRightOf="@+id/search_content"android:background="@drawable/button_bg"android:text="确定"android:textColor="#FFF"android:textSize="18sp" /></RelativeLayout><RelativeLayoutandroid:id="@+id/rl"android:layout_width="match_parent"android:layout_height="match_parent" android:visibility="invisible"><com.baidu.mapapi.map.MapViewandroid:id="@+id/mapview"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_centerInParent="true"android:clickable="true" /><LinearLayoutandroid:layout_width="40dp"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_marginBottom="120dp"android:layout_marginLeft="10dp"android:background="#FFF"android:orientation="vertical"android:paddingLeft="5dp"android:paddingRight="5dp" ><ImageViewandroid:id="@+id/add_scale"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:paddingBottom="12dp"android:paddingLeft="8dp"android:paddingRight="8dp"android:paddingTop="12dp"android:src="@drawable/ic_track_explore_zoomin_focus" /><Viewandroid:layout_width="match_parent"android:layout_height="0.1dp"android:background="#22000000" /><ImageViewandroid:id="@+id/low_scale"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:paddingBottom="12dp"android:paddingLeft="8dp"android:paddingRight="8dp"android:paddingTop="12dp"android:src="@drawable/ic_track_explore_zoomout_dis" /></LinearLayout><ImageViewandroid:id="@+id/my_location"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_marginBottom="60dp"android:layout_marginLeft="10dp"android:background="#FFF"android:padding="10dp"android:src="@drawable/main_icon_location" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginRight="10dp"android:layout_marginTop="60dp"android:orientation="vertical" ><ImageViewandroid:id="@+id/road_condition"android:layout_width="40dp"android:layout_height="40dp"android:background="@drawable/add_poi_map_selection_btn_pressed"android:scaleType="centerInside"android:src="@drawable/main_icon_roadcondition_off" /><ImageViewandroid:id="@+id/map_type"android:layout_width="40dp"android:layout_height="40dp"android:layout_marginTop="10dp"android:background="@drawable/add_poi_map_selection_btn_pressed"android:scaleType="centerInside"android:src="@drawable/main_icon_maplayers" /><ImageViewandroid:id="@+id/map_panorama"android:layout_width="40dp"android:layout_height="40dp"android:layout_marginTop="10dp"android:background="@drawable/add_poi_map_selection_btn_pressed"android:scaleType="centerInside"android:src="@drawable/main_map_icon_streetscape_selected" /></LinearLayout></RelativeLayout></LinearLayout>
源码:
package com.zhongqihong.mymap;import java.util.ArrayList;import java.util.List;import com.baidu.mapapi.map.BaiduMap;import com.baidu.mapapi.map.MapStatusUpdate;import com.baidu.mapapi.map.MapStatusUpdateFactory;import com.baidu.mapapi.map.MapView;import com.baidu.mapapi.map.MarkerOptions;import com.baidu.mapapi.overlayutil.BusLineOverlay;import com.baidu.mapapi.search.busline.BusLineResult;import com.baidu.mapapi.search.busline.BusLineResult.BusStation;import com.baidu.mapapi.search.busline.BusLineSearch;import com.baidu.mapapi.search.busline.BusLineSearchOption;import com.baidu.mapapi.search.busline.OnGetBusLineSearchResultListener;import com.baidu.mapapi.search.core.PoiInfo;import com.baidu.mapapi.search.core.SearchResult;import com.baidu.mapapi.search.poi.OnGetPoiSearchResultListener;import com.baidu.mapapi.search.poi.PoiCitySearchOption;import com.baidu.mapapi.search.poi.PoiDetailResult;import com.baidu.mapapi.search.poi.PoiResult;import com.baidu.mapapi.search.poi.PoiSearch;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.os.Bundle;import android.view.View;import android.view.Window;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.Toast;import android.widget.ZoomControls;/*** @author mikyou* 公交线路查询* */public class BusSearchActivity extends Activity implements OnClickListener{private MapView myMapView;private View defaultBaiduMapScaleButton=null;private View defaultBaiduMapLogo=null;private View defaultBaiduMapScaleUnit=null;private ImageView mapRoad,selectMapType,mapPanorama;private ImageView addScale,lowScale;private BaiduMap myBaiduMap;private String[] types={"普通地图","卫星地图","热力地图(已关闭)"};private float current;private EditText searchContent;private Button searchButton;private String cityName;//城市名private String busLine;//公交路线private List<String> busLineUidList;//公交路线的uid集合private int buslineIndex = 0;// 标记第几个路线private List<BusStation>stations;//用于存放某条公交线路中的所有站点信息private RelativeLayout rLayout;private PoiSearch poiSearch;private BusLineSearch busLineSearch;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_bus_search);initMapView();changeDefaultBaiduMapView();initSearchBusLine();}private void initSearchBusLine() {cityName=getIntent().getStringExtra("cityName");//这个是cityName是前面通过定位得到的城市名,也就是说自动默认为你查询你所处的城市的公交路线busLineUidList=new ArrayList<String>();poiSearch=PoiSearch.newInstance();//创建POI兴趣点检索对象poiSearch.setOnGetPoiSearchResultListener(poiSearchResultListener);//并且给该对象设置监听器,如果有结果返回就立即触发该回调方法返回兴趣点的uid集合busLineSearch=BusLineSearch.newInstance();//创建一个公交线路检索对象busLineSearch.setOnGetBusLineSearchResultListener(busLineSearchResultListener);//并且给该对象设置监听器,如果有结果返回就立即触发该回调方法,返回公交线路信息}/*** POI检索结果监听器*/OnGetPoiSearchResultListener poiSearchResultListener =new OnGetPoiSearchResultListener() {@Overridepublic void onGetPoiResult(PoiResult poiResult) {if (poiResult == null|| poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {// 没有找到检索结果Toast.makeText(BusSearchActivity.this, "未找到结果",Toast.LENGTH_LONG).show();return;}if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {// 检索到结果正常返回// 遍历所有poi,找到类型为公交线路的poibusLineUidList.clear();//先清空一下该uid集合,因为可能留有上一次中的数据for (PoiInfo poi : poiResult.getAllPoi()) {//遍历返回的所有的poi,这其中的poi有很多类型,很多数据就好比关键字搜索返回多种多样数据结果一样,并且返回的POI中还会带有一个uid,if (poi.type == PoiInfo.POITYPE.BUS_LINE|| poi.type == PoiInfo.POITYPE.SUBWAY_LINE) {//先在众多类型的数据中,筛选出公交线路类型,地铁线路类型busLineUidList.add(poi.uid);//然后在到筛选得到的poi中取出uid,并加入到公交线路集合中去}}searchBusline();}}@Overridepublic void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {}};/*** @author mikyou* 搜索公交线路* */private void searchBusline() {if (buslineIndex >= busLineUidList.size()) {//表示上一次的数据buslineIndex没有清空,所以就对buslineIndex进行初始化buslineIndex = 0;}if (buslineIndex >= 0 && buslineIndex < busLineUidList.size()&& busLineUidList.size() > 0) {//下面表示如果检索到了相应的公交线路,就返回true,否则返回false;这里的cityName就是传入的城市名,//cityName是通过MainActivity中的定位得到城市,所以也就实现了默认查询你所处城市的公交路线,//uid就传入通过poiSearch检索到的兴趣点中并筛选出的公交或地铁类型的uid,然后就通过OnGetBusLineSearchResultListener监听器//如果监听有公交线路信息,就返回一个true boolean flag = busLineSearch.searchBusLine((new BusLineSearchOption().city(cityName).uid(busLineUidList.get(buslineIndex))));if (flag) {Toast.makeText(BusSearchActivity.this, "检索成功~", 1000).show();} else {Toast.makeText(BusSearchActivity.this, "检索失败~", 1000).show();}buslineIndex++;}}/*** 公交信息查询结果监听器*/OnGetBusLineSearchResultListener busLineSearchResultListener=new OnGetBusLineSearchResultListener() {@Overridepublic void onGetBusLineResult(BusLineResult busLineResult) {if (busLineResult.error == SearchResult.ERRORNO.NO_ERROR) {//表示得到结果类型是NO_ERROR,没有错误,就说明返回了公交线路的信息rLayout.setVisibility(View.VISIBLE);myBaiduMap.clear();BusLineOverlay overlay = new MyBuslineOverlay(myBaiduMap);// 用于显示一条公交详情结果的Overlay,定义一个公交线路的图层用于显示公交线路overlay.setData(busLineResult);overlay.addToMap();// 将overlay添加到地图上overlay.zoomToSpan();// 缩放地图,使所有overlay都在合适的视野范围内myBaiduMap.setOnMarkerClickListener(overlay);// 公交线路名称stations=busLineResult.getStations();//通过getStations方法可以得到该条公交线路中途径的所有的站台/*for (int i=0;i<stations.size();i++) {toast("第"+(i+1)+"站: "+stations.get(i).getTitle());}toast("线路:"+busLineResult.getBusLineName()+" 首班车时间:"+busLineResult.getStartTime()+" 末班车时间:"+busLineResult.getEndTime());*/} else {//否则提示未找到结果Toast.makeText(BusSearchActivity.this, "抱歉,未找到结果",Toast.LENGTH_SHORT).show();}}};class MyBuslineOverlay extends BusLineOverlay {public MyBuslineOverlay(BaiduMap arg0) {super(arg0);}/*** 站点点击事件*/@Overridepublic boolean onBusStationClick(int position) {//对显示在地图上的公交图层设置监听事件,position就是传入的是位置序号MarkerOptions options = (MarkerOptions) getOverlayOptions().get(position);myBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(options.getPosition()));toast(stations.get(position).getTitle()+"站");//实现点击某个站点图标弹出该站点的名称return true;}}@Overrideprotected void onResume() {super.onResume();myMapView.onResume();}@Overrideprotected void onPause() {super.onPause();myMapView.onPause();}@Overrideprotected void onDestroy() {super.onDestroy();poiSearch.destroy();// 释放检索对象资源busLineSearch.destroy();// 释放检索对象资源myMapView.onDestroy();}private void initMapView() {registerAllViewId();registerAllViewEvent();}private void registerAllViewEvent() {addScale.setOnClickListener(this);lowScale.setOnClickListener(this);mapRoad.setOnClickListener(this);selectMapType.setOnClickListener(this);searchButton.setOnClickListener(this);}private void registerAllViewId() {myMapView=(MapView) findViewById(R.id.mapview);addScale=(ImageView) findViewById(R.id.add_scale);lowScale=(ImageView) findViewById(R.id.low_scale);mapRoad=(ImageView) findViewById(R.id.road_condition);selectMapType=(ImageView) findViewById(R.id.map_type);searchContent=(EditText) findViewById(R.id.search_content);searchButton=(Button) findViewById(R.id.ok_btn);rLayout=(RelativeLayout) findViewById(R.id.rl);}/*** @author zhongqihong* 修改默认百度地图的View* * */private void changeDefaultBaiduMapView() {changeInitialzeScaleView();//改变默认百度地图初始加载的地图比例//设置隐藏缩放和扩大的百度地图的默认的比例按钮for (int i = 0; i < myMapView.getChildCount(); i++) {//遍历百度地图中的所有子View,找到这个扩大和缩放的按钮控件View,然后设置隐藏View即可View child=myMapView.getChildAt(i);if (child instanceof ZoomControls) {defaultBaiduMapScaleButton=child;//该defaultBaiduMapScaleButton子View是指百度地图默认产生的放大和缩小的按钮,得到这个Viewbreak;}}defaultBaiduMapScaleButton.setVisibility(View.GONE);//然后将该View的Visiblity设为不存在和不可见,即隐藏defaultBaiduMapLogo =myMapView.getChildAt(1);//该View是指百度地图中默认的百度地图的Logo,得到这个ViewdefaultBaiduMapLogo.setPadding(300, -10, 100, 100);//设置该默认Logo View的位置,因为这个该View的位置会影响下面的刻度尺单位View显示的位置myMapView.removeViewAt(1);//最后移除默认百度地图的logo ViewdefaultBaiduMapScaleUnit=myMapView.getChildAt(2);//得到百度地图的默认单位刻度的ViewdefaultBaiduMapScaleUnit.setPadding(100, 0, 115,200);//最后设置调整百度地图的默认单位刻度View的位置}private void changeInitialzeScaleView() {myBaiduMap=myMapView.getMap();//改变百度地图的放大比例,让首次加载地图就开始扩大到500米的距离MapStatusUpdate factory=MapStatusUpdateFactory.zoomTo(15.0f);myBaiduMap.animateMapStatus(factory);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.road_condition:if (myBaiduMap.isTrafficEnabled()) {myBaiduMap.setTrafficEnabled(false);mapRoad.setImageResource(R.drawable.main_icon_roadcondition_off);}else{myBaiduMap.setTrafficEnabled(true);mapRoad.setImageResource(R.drawable.main_icon_roadcondition_on);}break;case R.id.add_scale:current+=0.5f;MapStatusUpdate factory=MapStatusUpdateFactory.zoomTo(15.0f+current);myBaiduMap.animateMapStatus(factory);//设置百度地图的缩放效果动画animateMapStatusbreak;case R.id.low_scale:current-=0.5f;MapStatusUpdate factory2=MapStatusUpdateFactory.zoomTo(15.0f+current);myBaiduMap.animateMapStatus(factory2);break;case R.id.map_type:AlertDialog.Builder builder=new AlertDialog.Builder(this);builder.setIcon(R.drawable.icon).setTitle("请选择地图的类型").setItems(types, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String select=types[which];if (select.equals("普通地图")) { myBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);}else if (select.equals("卫星地图")) {myBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);}else if (select.equals("热力地图(已关闭)")||select.equals("热力地图(已打开)")) {if(myBaiduMap.isBaiduHeatMapEnabled()) {myBaiduMap.setBaiduHeatMapEnabled(false);Toast.makeText(BusSearchActivity.this, "热力地图已关闭", 0).show();types[which]="热力地图(已关闭)";}else {myBaiduMap.setBaiduHeatMapEnabled(true);Toast.makeText(BusSearchActivity.this, "热力地图已打开", 0).show();types[which]="热力地图(已打开)";}}}}).show();break;case R.id.ok_btn:busLine=searchContent.getText().toString();poiSearch.searchInCity(new PoiCitySearchOption().city(cityName).keyword(busLine));break;default:break;}}private void toast(String str) {Toast.makeText(BusSearchActivity.this, str, 0).show();}}
实现的效果:
demo使用注意:查询时查询的方式用"的"关键字隔开城市名和公交或地铁线路名,如:北京的地铁一号线,北京的211路.
点击下载Demo