中级实训Android学习记录——Poi检索、距离计算、调起百度地图

学习记录 2020/12/23

  • 之前过程:Android Studio的简单应用——更改地图类型、显示定位
  • 百度API的简单应用——PoiSearch
  1. 创建POI检索实例

    在SDK组件初始化之后使用下列代码即可:

    mPoiSearch = PoiSearch.newInstance();
    
  2. 创建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,这样有利于简化代码

  3. 设置检索监听器

    mPoiSearch.setOnGetPoiSearchResultListener(listener);
    
  4. 设置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));
    
    
  5. 释放检索实例

    重要的声明周期管理:

    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);

以上的代码即可完全地调起百度地图并直接进行步行导航

  • 综合教程——摇一摇地图
  1. 制作百度地图的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);
         });
     }
    
  2. 制作摇一摇

    初始化

    // ---------------------------------初始化摇一摇--------------------------------------- //
    
    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);
    
        }
    
  3. 使用摇一摇调用POI检索,使用recyclerView调起百度地图

    摇一摇中onSensorChanged函数中在开始摇晃时加入POI检索函数:searchPoiNearBy

    recyclerView的每个holder加入调起百度地图的监听器;

posted @ 2020-12-23 19:54  沐锋丶  阅读(337)  评论(0编辑  收藏  举报