中级实训Android学习记录——Poi检索、距离计算、调起百度地图
学习记录 2020/12/23
- 之前过程:Android Studio的简单应用——更改地图类型、显示定位
- 百度API的简单应用——PoiSearch
创建POI检索实例
在SDK组件初始化之后使用下列代码即可:
mPoiSearch = PoiSearch.newInstance();
创建POI检索监听器
在同一个Activity中编写以下代码:
OnGetPoiSearchResultListener listener = new OnGetPoiSearchResultListener() { @Override public void onGetPoiResult(PoiResult poiResult) { } @Override public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailSearchResult) { } @Override public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) { } //废弃 @Override public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) { } };
其中
onGetPoiResult
是主要的回调函数,所以涉及到搜索结果的操作基本都放在这个函数中进行,在我的源码中,我把MainActivity
当作一个OnGetPoiSearchResultListener
,这样有利于简化代码设置检索监听器
mPoiSearch.setOnGetPoiSearchResultListener(listener);
设置
PoiCitySearchOption
,发起检索请求/** * PoiCiySearchOption 设置检索属性 * city 检索城市 * keyword 检索内容关键字 * pageNum 分页页码 */ mPoiSearch.searchInCity(new PoiCitySearchOption() .city("北京") //必填 .keyword("美食") //必填 .pageNum(10));
在我的源码中,使用的是周边检索,应用的接口应该是:
/** * 以天安门为中心,搜索半径100米以内的餐厅 */ mPoiSearch.searchNearby(new PoiNearbySearchOption() .location(new LatLng(39.915446, 116.403869)) .radius(100); //支持多个关键字并集检索,不同关键字间以$符号分隔,最多支持10个关键字检索。如:”银行$酒店” .keyword("餐厅") .pageNum(10));
释放检索实例
重要的声明周期管理:
mPoiSearch.destroy();
- 百度地图的简单应用——距离计算
两点距离计算
根据用户指定的两个坐标点,计算这两个点之间的直线实际地理距离。
返回值类型:double
返回值单位:米
核心代码如下:
//计算p1、p2两点之间的直线距离,单位:米 DistanceUtil. getDistance(p1, p2);
其中p1和p2都是
LatLng
的对象
- 百度地图的简单应用——调起百度地图
由于不可能设计的APP面向的需求是寻找附近的一个可供娱乐的地方,所以导航的功能可以直接使用现成的百度地图来提供
我们使用的是步行导航:
//定义起终点坐标(天安门和百度大厦) LatLng startPoint = new LatLng(39.915291, 116.403857); LatLng endPoint = new LatLng(40.056858, 116.308194); //构建导航参数 NaviParaOption para = new NaviParaOption() .startPoint(startPoint) .endPoint(endPoint) .startName("天安门") .endName("百度大厦"); //调起百度地图 try { BaiduMapNavigation.openBaiduMapWalkNavi(para, this); } catch (BaiduMapAppNotSupportNaviException e) { e.printStackTrace(); //调起失败的处理 } //调起结束时及时调用finish方法以释放相关资源 BaiduMapNavigation.finish(this);
以上的代码即可完全地调起百度地图并直接进行步行导航
- 综合教程——摇一摇地图
制作百度地图的API的综合运用——显示定位、POI检索、距离计算、调起百度地图
关键代码:
权限:
<!-- 以下权限开启地图服务 --> <!-- 访问网络,进行地图相关业务数据请求,包括地图数据,路线规划,POI检索等 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 获取网络状态,根据网络状态切换进行数据请求网络转换 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 读取外置存储。如果开发者使用了so动态加载功能并且把so文件放在了外置存储区域,则需要申请该权限,否则不需要 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 写外置存储。如果开发者使用了离线地图,并且数据写在外置存储区域,则需要申请该权限 --> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 以下权限用于开启定位服务 --> <!-- 这个权限用于进行网络定位 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 这个权限用于访问GPS定位 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- 以下权限用于开启定位服务 --> <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"/>
显示定位:
// ----------------------------------- 初始化百度地图 --------------------------------- // mMapView = findViewById(R.id.bmapView); mTextView = findViewById(R.id.tv); mPoiSearch = PoiSearch.newInstance(); mPoiSearch.setOnGetPoiSearchResultListener(this); // 更改地图类型 mBaiduMap = mMapView.getMap(); mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE); // 设置定位服务开始 mBaiduMap.setMyLocationEnabled(true); //定位初始化 mLocationClient = new LocationClient(getApplicationContext()); //通过LocationClientOption设置LocationClient相关参数 LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors); // 定位模式是仅限设备模式,也就是仅允许GPS来定位。 option.setOpenGps(true); // 打开gps option.setCoorType("bd09ll"); // 设置坐标类型 option.setScanSpan(1000); //设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化就会主动回调给开发者 option.setIsNeedAddress(true); //可选,是否需要地址信息,默认为不需要,即参数为false //如果开发者需要获得当前点的地址信息,此处必须为true option.setNeedNewVersionRgc(true); //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true //设置locationClientOption mLocationClient.setLocOption(option); //注册LocationListener监听器 MyLocationListener myLocationListener = new MyLocationListener(); mLocationClient.registerLocationListener(myLocationListener); //开启地图定位图层 mLocationClient.start(); // 搜索时不重复,使用HashSet来支持 mHashLocStr = new HashSet<>(); // 一开始搜索的半径和接收的结果数 mRadius = 1000; mPageCapacity = 10; // ----------------------------------------------------------------------------------- //
POI检索:
// 搜索附近的娱乐设施 private void searchPoiNearBy() { String cityStr = mCity; // 获取检索关键字 String keyWordStr = "娱乐"; if (TextUtils.isEmpty(cityStr) || TextUtils.isEmpty(keyWordStr)) { return; } LatLng ll = new LatLng(mBDLocation.getLatitude(), mBDLocation.getLongitude()); // 搜索附近的娱乐场所 mPoiSearch.searchNearby((new PoiNearbySearchOption()) .location(ll) .keyword(keyWordStr) .pageCapacity(mPageCapacity) .pageNum(0) .radius(mRadius)); }
调起百度地图:
@Override public void onBindViewHolder(@NonNull AddressHolder holder, int position) { //定义起终点坐标 LatLng startPoint = new LatLng(startLocation.getLatitude(), startLocation.getLongitude()); LatLng endPoint = list.get(position).getLocation(); int distance = (int)DistanceUtil.getDistance(startPoint, endPoint); String locStr = list.get(position).getName() + ", 距离自己:" + distance + " m"; holder.textView.setText(locStr); holder.textView.setOnClickListener(v -> { Toast.makeText(mContext, "点我就跳转到别的APP咯", Toast.LENGTH_SHORT).show(); //构建导航参数 NaviParaOption para = new NaviParaOption() .startPoint(startPoint) .endPoint(endPoint) .startName("我的位置") .endName(list.get(position).getName()); //调起百度地图 try { BaiduMapNavigation.openBaiduMapWalkNavi(para, mContext); } catch (BaiduMapAppNotSupportNaviException e) { e.printStackTrace(); //调起失败的处理 } //调起结束时及时调用finish方法以释放相关资源 BaiduMapNavigation.finish(mContext); }); }
制作摇一摇
初始化
// ---------------------------------初始化摇一摇--------------------------------------- // mHandler = new MyHandler(this); //初始化SoundPool mSoundPool = new SoundPool(1, AudioManager.STREAM_SYSTEM, 5); mWeiChatAudio = mSoundPool.load(this, R.raw.weichat_audio, 1); //获取Vibrator震动服务 mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); // 摇一摇的两个分离界面 mTopLayout = findViewById(R.id.top_layout); mBottomLayout = findViewById(R.id.bottom_layout); //获取 SensorManager 负责管理传感器 mSensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE)); if (mSensorManager != null) { //获取加速度传感器 mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); if (mAccelerometerSensor != null) { mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_UI); } } // ----------------------------------------------------------------------------------- //
监听Handler:
/** * handler 接收摇一摇产生的信息并作出对应的操作 * START_SHAKE 开始摇晃 * AGAIN_SHAKE 没结束摇晃之前再次摇晃 * END_SHAKE 结束摇晃 */ private static class MyHandler extends Handler { private WeakReference<MainActivity> mReference; private MainActivity mActivity; public MyHandler(MainActivity activity) { mReference = new WeakReference<MainActivity>(activity); if (mReference != null) { mActivity = mReference.get(); } } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case START_SHAKE: //This method requires the caller to hold the permission VIBRATE. mActivity.mVibrator.vibrate(300); //发出提示音 mActivity.mSoundPool.play(mActivity.mWeiChatAudio, 1, 1, 0, 0, 1); mActivity.startAnimation(false);//参数含义: (不是回来) 也就是说两张图片分散开的动画 break; case AGAIN_SHAKE: mActivity.mVibrator.vibrate(300); break; case END_SHAKE: //整体效果结束, 将震动设置为false mActivity.isShake = false; // 展示上下两种图片回来的效果 mActivity.startAnimation(true); break; } } }
编写监听函数:
/////////////////////////////////////////////////////////////////////////// // SensorEventListener回调方法 /////////////////////////////////////////////////////////////////////////// @Override public void onSensorChanged(SensorEvent event) { int type = event.sensor.getType(); if (type == Sensor.TYPE_ACCELEROMETER) { //获取三个方向值 float[] values = event.values; float x = values[0]; float y = values[1]; float z = values[2]; if ((Math.abs(x) > 17 || Math.abs(y) > 17 || Math .abs(z) > 17) && !isShake) { isShake = true; Thread thread = new Thread() { @Override public void run() { super.run(); try { Log.d(TAG, "onSensorChanged: 摇动"); searchPoiNearBy(); //开始震动 发出提示音 展示动画效果 mHandler.obtainMessage(START_SHAKE).sendToTarget(); Thread.sleep(500); //再来一次震动提示 mHandler.obtainMessage(AGAIN_SHAKE).sendToTarget(); Thread.sleep(500); mHandler.obtainMessage(END_SHAKE).sendToTarget(); } catch (InterruptedException e) { e.printStackTrace(); } } }; thread.start(); } } }
编写动画:
/** * 开启 摇一摇动画 * * @param isBack 是否是返回初识状态 */ private void startAnimation(boolean isBack) { //动画坐标移动的位置的类型是相对自己的 int type = Animation.RELATIVE_TO_PARENT; float topFromY; float topToY; float bottomFromY; float bottomToY; if (!isBack) { topFromY = -0.5f; topToY = 0; bottomFromY = 0.6f; bottomToY = 0; } else { topFromY = 0; topToY = -0.5f; bottomFromY = 0; bottomToY = 0.6f; } //上面图片的动画效果 TranslateAnimation topAnim = new TranslateAnimation( type, 0, type, 0, type, topFromY, type, topToY ); topAnim.setDuration(200); //动画终止时停留在最后一帧~不然会回到没有执行之前的状态 topAnim.setFillAfter(true); //底部的动画效果 TranslateAnimation bottomAnim = new TranslateAnimation( type, 0, type, 0, type, bottomFromY, type, bottomToY ); bottomAnim.setDuration(200); bottomAnim.setFillAfter(true); //大家一定不要忘记, 当要回来时, 我们中间的两根线需要GONE掉 if (isBack) { bottomAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { } }); } //设置动画 mTopLayout.startAnimation(topAnim); mBottomLayout.startAnimation(bottomAnim); }
使用摇一摇调用POI检索,使用
recyclerView
调起百度地图摇一摇中
onSensorChanged
函数中在开始摇晃时加入POI检索函数:searchPoiNearBy
;
recyclerView
的每个holder加入调起百度地图的监听器;