文章内容已经过时~大家去百度官方api学习。
http://developer.baidu.com/map/
http://lbsyun.baidu.com/sdk/download
功能描述:获取手机自身附近的兴趣点(Poi, 之后使用Poi表示兴趣点)列表,显示在listview中先上效果图
显而易见的是,图中只有一个简单的listview,然后每个item分别包含Poi的名字,地址和手机到poi所在的距离。由于我在学校里,附近只有5个ATM。
好了如果你看到的这个效果是你所需要的功能,内心是不是有点小激动呢?
现在我们来分析这个实现的思路:
零,做好之前的准备工作
一,首先是要得到手机自身的位置
二,然后根据这个位置和你要找的POI的名字来得到附近的POI列表
实现的步骤:
向项目中加入百度地图SDK。
登录后来访问 下载地址http://developer.baidu.com/map/sdkandev-download.htm全部商情下载
下载后解压成
在BaiduMap_AndroidSDK_v2.4.1_Sample - > BaiduMapsApiDemo - >库以及库 - > armeabi中
将 baidumapapi_v2_4_1.jar locSDK_3.1.jar libBaiduMapSDK_v2_4_1.so liblocSDK3.so以相同模式拷到我们当前新建的项目中
然后添加到构建路径
然后记得申请的关键:http://developer.baidu.com/map/android-mobile-apply-key.htm跟着提示走,这里就不叙述了。
东西准备好了,开始编写代码
首先当然是MainActivity.java
public class MainActivity extends Activity { final static String TAG = "MainActivity"; private static final int MSG_SELFPOINT = 1; private static final int MSG_MPOIINFOLIST = 2; private static final String POI_NAME = "ATM"; // 搜索指定兴趣点名称 private static final int SCAN_SPAN = 60 * 1000; // 刷新时间 private static final int POI_DISTANCE = 1000; // 搜索半径 private LocationClient locationClient = null; private MKSearch mMKSearch = null; private GeoPoint selfPoint = null; // 自身经纬度 private ListView poiInfoList; private List<poiinfo> mPoiInfoList = null; @SuppressLint("HandlerLeak") private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_SELFPOINT: // 获得自身经纬度 default: Double[] locNum = (Double[]) msg.obj; // 用给定的经纬度构造一个GeoPoint(纬度,经度) selfPoint = new GeoPoint((int) (locNum[0] * 1E6), (int) (locNum[1] * 1E6)); // 执行搜索周边兴趣点列表 mMKSearch.poiSearchNearBy(POI_NAME, selfPoint, POI_DISTANCE); break; case MSG_MPOIINFOLIST: // 获得周边兴趣点列表 PoiAdapter adapter = new PoiAdapter(getApplicationContext(), mPoiInfoList); adapter.notifyDataSetChanged(); poiInfoList.setAdapter(adapter); break; } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initMapManagerAndMKSearch(); setContentView(R.layout.activity_main); initViews(); startLocationClient(); } @Override protected void onDestroy() { super.onDestroy(); if (locationClient != null && locationClient.isStarted()) { locationClient.stop(); locationClient = null; } } /** * 使用地图sdk前需先初始化BMapManager. BMapManager是全局的,可为多个MapView共用,它需要地图模块创建前创建, * 并在地图地图模块销毁后销毁,只要还有地图模块在使用,BMapManager就不应该销毁 */ private void initMapManagerAndMKSearch() { MyApplication app = (MyApplication) this.getApplication(); if (app.mBMapManager == null) { app.mBMapManager = new BMapManager(getApplicationContext()); /** * 如果BMapManager没有初始化则初始化BMapManager */ app.mBMapManager.init(new MyApplication.MyGeneralListener()); } mMKSearch = new MKSearch(); mMKSearch.init(app.mBMapManager, new MKSearchListener() { @Override public void onGetWalkingRouteResult(MKWalkingRouteResult result, int iError) { // 步行路线搜索结果 } @Override public void onGetTransitRouteResult(MKTransitRouteResult result, int iError) { // 公交换乘路线搜索结果 } @Override public void onGetSuggestionResult(MKSuggestionResult arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetShareUrlResult(MKShareUrlResult arg0, int arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onGetPoiResult(MKPoiResult result, int type, int iError) { // POI搜索结果(范围检索、城市POI检索、周边检索) if (result == null) { Log.i(TAG, "周围一定范围内没有检索出POI目标"); Toast.makeText(getApplicationContext(), "周围一定范围内没有检索出POI目标", Toast.LENGTH_SHORT).show(); return; } mPoiInfoList = new ArrayList<poiinfo>(); PoiInfo mPoiInfo = null; for (MKPoiInfo mMKPoiInfo : result.getAllPoi()) { // 计算自身与目的地之间的距离 int distanceM = (int) DistanceUtil.getDistance(selfPoint, mMKPoiInfo.pt); mPoiInfo = new PoiInfo(mMKPoiInfo.name, mMKPoiInfo.address, distanceM); mPoiInfoList.add(mPoiInfo); } Message.obtain(handler, MSG_MPOIINFOLIST).sendToTarget(); } @Override public void onGetPoiDetailSearchResult(int arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetDrivingRouteResult(MKDrivingRouteResult result, int iError) { // 驾车路线搜索结果 } @Override public void onGetBusDetailResult(MKBusLineResult arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetAddrResult(MKAddrInfo result, int iError) { // 根据经纬度搜索地址信息结果 } }); } private void startLocationClient() { locationClient = new LocationClient(getApplicationContext()); locationClient.setLocOption(setLocationOption()); // 注册位置监听器 locationClient.registerLocationListener(new BDLocationListener() { @Override public void onReceiveLocation(BDLocation location) { if (location == null) { return; } double latitude = location.getLatitude(); // 纬度 double longitude = location.getLongitude(); // 经度 Double[] locNum = { latitude, longitude }; Message.obtain(handler, MSG_SELFPOINT, locNum).sendToTarget(); locationClient.stop(); // 停止查询自身经纬度 } @Override public void onReceivePoi(BDLocation location) { } }); locationClient.start(); // 开始查询自身经纬度 locationClient.requestLocation(); } private LocationClientOption setLocationOption() { // 设置定位条件 LocationClientOption option = new LocationClientOption(); option.setServiceName("com.baidu.location.service_v2.9"); // 需要地址信息,设置为其他任何值(string类型,且不能为null)时,都表示无地址信息。 option.setAddrType("all"); // 设置是否返回POI的电话和地址等详细信息。默认值为false,即不返回POI的电话和地址信息。 option.setPoiExtraInfo(false); // 设置产品线名称。强烈建议您使用自定义的产品线名称,方便我们以后为您提供更高效准确的定位服务。 option.setProdName("定位我当前的位置"); // 设置GPS,使用gps前提是用户硬件打开gps。默认是不打开gps的。 option.setOpenGps(true); // 定位的时间间隔,单位:ms // 当所设的整数值大于等于1000(ms)时,定位SDK内部使用定时定位模式。 option.setScanSpan(SCAN_SPAN); // 查询范围,默认值为500,即以当前定位位置为中心的半径大小。 option.setPoiDistance(POI_DISTANCE); // 禁用启用缓存定位数据 option.disableCache(true); // 坐标系类型,百度手机地图对外接口中的坐标系默认是bd09ll option.setCoorType("bd09ll"); // 设置最多可返回的POI个数,默认值为3。由于POI查询比较耗费流量,设置最多返回的POI个数,以便节省流量。 option.setPoiNumber(0); // 设置定位方式的优先级。 // 当gps可用,而且获取了定位结果时,不再发起网络请求,直接返回给用户坐标。这个选项适合希望得到准确坐标位置的用户。如果gps不可用,再发起网络请求,进行定位。 option.setPriority(LocationClientOption.NetWorkFirst); return option; } private void initViews() { poiInfoList = (ListView) findViewById(R.id.lv_poiInfoList); } } </poiinfo></poiinfo>
从onCreate走起,先初始化BMapManager,然后加载布局,最后初始化LocationClient配置参数start()以及requestLocation()后
通过registerLocationListener中onReceiveLocation()可获得自身经纬度,经纬度手柄一下调用MKSearch.poiSearchNearBy()搜索周边兴趣点列表
通过MKSearchListener中onGetPoiResult()列表配置。再处理一下加载UI。
然后是MyApplication.java
public class MyApplication extends Application { private static MyApplication mInstance = null; public boolean m_bKeyRight = true; BMapManager mBMapManager = null; @Override public void onCreate() { super.onCreate(); mInstance = this; initEngineManager(this); } public void initEngineManager(Context context) { if (mBMapManager == null) { mBMapManager = new BMapManager(context); } if (!mBMapManager.init(new MyGeneralListener())) { Toast.makeText(MyApplication.getInstance().getApplicationContext(), "BMapManager 初始化错误!", Toast.LENGTH_LONG).show(); } } public static MyApplication getInstance() { return mInstance; } // 常用事件监听,用来处理通常的网络错误,授权验证错误等 static class MyGeneralListener implements MKGeneralListener { @Override public void onGetNetworkState(int iError) { if (iError == MKEvent.ERROR_NETWORK_CONNECT) { Toast.makeText( MyApplication.getInstance().getApplicationContext(), "您的网络出错啦!", Toast.LENGTH_LONG).show(); } else if (iError == MKEvent.ERROR_NETWORK_DATA) { Toast.makeText( MyApplication.getInstance().getApplicationContext(), "输入正确的检索条件!", Toast.LENGTH_LONG).show(); } // ... } @Override public void onGetPermissionState(int iError) { // 非零值表示key验证未通过 if (iError != 0) { // 授权Key错误: Toast.makeText( MyApplication.getInstance().getApplicationContext(), "请在 DemoApplication.java文件输入正确的授权Key,并检查您的网络连接是否正常!error: " + iError, Toast.LENGTH_LONG).show(); MyApplication.getInstance().m_bKeyRight = false; } else { MyApplication.getInstance().m_bKeyRight = true; Toast.makeText( MyApplication.getInstance().getApplicationContext(), "key认证成功", Toast.LENGTH_LONG).show(); } } } }
然后清单文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="10" /> <permission android:name="android.permission.BAIDU_LOCATION_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application android:name="MyApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="SebBBgHgrqTVjr8WXAYP9TCl" /> <activity android:name="com.example.android.MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.baidu.location.f" android:enabled="true" android:permission="android.permission.BAIDU_LOCATION_SERVICE" android:process=":remote" > <intent-filter> <action android:name="com.baidu.location.service_v2.4" /> </intent-filter> </service> </application> </manifest>
这里注意需要在中的android:值填写关键值还有一个百度自己的位置服务的注册。
最后布局文件:activity_main.xml和item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.baidu.mapapi.map.MapView android:id="@+id/map_View" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:visibility="gone" /> <ListView android:id="@+id/lv_poiInfoList" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#fff" /> </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/tv_poiName" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_poiAddress" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_poiDistance" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
列表适配器:
public class PoiAdapter extends BaseAdapter { List<poiinfo> poiInfoList; @SuppressWarnings("unused") private Context context; private LayoutInflater inflater; public PoiAdapter(Context context, List<poiinfo> poiInfoList) { this.poiInfoList = poiInfoList; this.context = context; inflater = LayoutInflater.from(context); // 创建视图容器并设置上下文 } @Override public int getCount() { return poiInfoList != null ? poiInfoList.size() : 0; } @Override public Object getItem(int postion) { return poiInfoList != null ? poiInfoList.get(postion) : null; } @Override public long getItemId(int postion) { return postion; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = inflater.inflate(R.layout.item, null); viewHolder.poiName = (TextView) convertView.findViewById(R.id.tv_poiName); viewHolder.poiAddress = (TextView) convertView.findViewById(R.id.tv_poiAddress); viewHolder.poiDistance = (TextView) convertView.findViewById(R.id.tv_poiDistance); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } PoiInfo mPoiInfo = poiInfoList.get(position); viewHolder.poiName.setText(mPoiInfo.getName()); viewHolder.poiAddress.setText(mPoiInfo.getAddress()); viewHolder.poiDistance.setText(mPoiInfo.getDistance().toString()); return convertView; } final class ViewHolder { TextView poiName; TextView poiAddress; TextView poiDistance; } } </poiinfo></poiinfo>
列表实体:
package com.example.android; public class PoiInfo { private String name; private String address; private Integer distance; public PoiInfo() { super(); } public PoiInfo(String name, String address, Integer distance) { super(); this.name = name; this.address = address; this.distance = distance; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getDistance() { return distance; } public void setDistance(Integer distance) { this.distance = distance; } @Override public String toString() { return "POIInfo [name=" + name + ", address=" + address + ", distance=" + distance + "]"; } }
到这里就完成了。
然后声明一下由于才刚学1个月的android开发,本人水平有限,对于这个功能,应该还有不足之处和一些BUG,
做出这个demo花了我6个小时时间编码,查阅百度地图api以及一些博客。写出这文章用了2个小时(第一次写-_-||)。
虽然效率很慢,但是我能感觉到自己水平略有提升,在这里希望和我一样正在奋斗的程序员继续加油。