浅谈百度地图的简单开发再续前缘之公交,地铁路线检索查询(六)
百度地图,公交地铁线路查询,POI检索,Android2016-05-27
关于百度地图的简单开发前段时间,写过一个小系列的博客关于百度地图的基本地图,定位,全景,导航等功能做了简单的介绍.从今天开始又将准备一期有关百度地图的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() { @Override public 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,找到类型为公交线路的poi busLineUidList.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(); } }
/** * 公交信息查询结果监听器 */ OnGetBusLineSearchResultListener busLineSearchResultListener=new OnGetBusLineSearchResultListener() { @Override public 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="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFF" android:padding="10dp" > <ImageView android: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" /> <EditText android: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" /> <Button android: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> <RelativeLayout android:id="@+id/rl" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" > <com.baidu.mapapi.map.MapView android:id="@+id/mapview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:clickable="true" /> <LinearLayout android: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" > <ImageView android: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" /> <View android:layout_width="match_parent" android:layout_height="0.1dp" android:background="#22000000" /> <ImageView android: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> <ImageView android: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" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:layout_marginTop="60dp" android:orientation="vertical" > <ImageView android: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" /> <ImageView android: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" /> <ImageView android: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; @Override protected 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() { @Override public 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,找到类型为公交线路的poi busLineUidList.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(); } } @Override public 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() { @Override public 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); } /** * 站点点击事件 */ @Override public boolean onBusStationClick(int position) {//对显示在地图上的公交图层设置监听事件,position就是传入的是位置序号 MarkerOptions options = (MarkerOptions) getOverlayOptions().get(position); myBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(options.getPosition())); toast(stations.get(position).getTitle()+"站");//实现点击某个站点图标弹出该站点的名称 return true; } } @Override protected void onResume() { super.onResume(); myMapView.onResume(); } @Override protected void onPause() { super.onPause(); myMapView.onPause(); } @Override protected 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是指百度地图默认产生的放大和缩小的按钮,得到这个View break; } } defaultBaiduMapScaleButton.setVisibility(View.GONE);//然后将该View的Visiblity设为不存在和不可见,即隐藏 defaultBaiduMapLogo =myMapView.getChildAt(1);//该View是指百度地图中默认的百度地图的Logo,得到这个View defaultBaiduMapLogo.setPadding(300, -10, 100, 100);//设置该默认Logo View的位置,因为这个该View的位置会影响下面的刻度尺单位View显示的位置 myMapView.removeViewAt(1);//最后移除默认百度地图的logo View defaultBaiduMapScaleUnit=myMapView.getChildAt(2);//得到百度地图的默认单位刻度的View defaultBaiduMapScaleUnit.setPadding(100, 0, 115,200);//最后设置调整百度地图的默认单位刻度View的位置 } private void changeInitialzeScaleView() { myBaiduMap=myMapView.getMap();//改变百度地图的放大比例,让首次加载地图就开始扩大到500米的距离 MapStatusUpdate factory=MapStatusUpdateFactory.zoomTo(15.0f); myBaiduMap.animateMapStatus(factory); } @Override public 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);//设置百度地图的缩放效果动画animateMapStatus break; 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() { @Override public 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路.