美文网首页Android开发经验谈程序员
六、android百度地图之导航(终结篇)

六、android百度地图之导航(终结篇)

作者: 猫儿不吃鱼鱼 | 来源:发表于2017-11-21 14:54 被阅读0次
    导航
    四、android百度地图之导航(环境的配置)
    五、android百度地图之导航(代码的拆分和工具类的封装)
    六、android百度地图之导航(终结篇)

    关于导航进过前两篇文章的铺垫,终于迎来了结尾。其实通过前面两篇文章的讲解,我相信很多人已经可以完成导航的功能了,但是还是有少部分同学有点疑惑,所以通过这篇文章我希望可以帮助那少部分也顺利的完成导航。

    一、起点终点页面

    要开始导航,首先我们要知道起点和终点分别是什么地方。所以我们首先需要一个这样的页面来进行输入。是的,页面相当的简单。所以我就直接放图,反正大家分分钟可以撸几十个这样的页面。


    输入起点和终点并开始导航

    二、进行初始化

    在完成页面后,我们就要对导航做初始化的工作了,首先我们先声明以下属性:

        @Bind(R.id.toolbar)
        Toolbar mToolbar;
        @Bind(R.id.starting_point)
        EditText startingPointName;
        @Bind(R.id.end_point)
        EditText endPointName;
    
        /**
         * 系统SD卡根目录路径
         */
        private String mSDCardPath = null;
    
        /**
         * 应用在SD卡中的目录名
         */
        private String APP_FOLDER_NAME = "HljtNavigation";
    
        /**
         * 导航工具类
         */
        private NavigationUtil navigationUtil;
    
        /**
         * 创建地理编码检索实例-起点
         */
        private GeoCoder geoCoderStarting = GeoCoder.newInstance();
    
        /**
         * 创建地理编码检索实例-终点
         */
        private GeoCoder geoCoderEnd = GeoCoder.newInstance();
    
        /**
         * 起点和终点的经纬度集合
         */
        public static Map<String,Double> naviMap = new HashMap<>();
    
        /**
         * 存储起点和终点的经纬度是否都编码成功
         */
        public static Map<String,Integer> typeMap = new HashMap<>();
    

    然后我们需要先写两个针对SD卡的方法,放别是初始化SD卡和得到SD卡的目录:

        /**
         * 初始化SD卡
         * @return
         */
        private boolean initDirs() {
            mSDCardPath = getSdcardDir();
            if (mSDCardPath == null) {
                return false;
            }
            File file = new File(mSDCardPath, APP_FOLDER_NAME);
            if (!file.exists()) {
                try {
                    file.mkdir();
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
        }
    
        /**
         * 得到SD卡目录
         * @return
         */
        @Nullable
        private String getSdcardDir() {
            if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
                return Environment.getExternalStorageDirectory().toString();
            }
            return null;
        }
    

    现在我们在onCreate方法或者定义一个放在onCreate方法中的init方法中去进行初始化:

       public void init() {
            NavigationRoutePlanListener.activityList.add(this);
            if (initDirs()) {
                navigationUtil = new NavigationUtil(this,mSDCardPath,APP_FOLDER_NAME);
                navigationUtil.initNavi();
            }
        }
    

    在经过以上的一系列工作后就可以去监听输入的起点和终点,点击开始导航了,有不少同学仿佛已经看到了胜利的曙光。然而,大家先刹刹车,想想还漏了什么。我们想想,导航根据输入的起点和终点就完成规划了吗?不是这样的,它其实是把起点和终点的经纬度拿去做的计算,所以我们还差地理编码这一步,这一步就是将输入的起点和终点转为对应的经纬度,这样才可以计算并导航。细心的同学在上面的代码中会发现在定义属性的时候已经获取了两个GeoCoder实例,现在就到了他们大显身手的时候了。代码如下:

    geoCoderStarting.setOnGetGeoCodeResultListener(new GeoCodeStartingListener());
                    geoCoderStarting.geocode(new GeoCodeOption()
                            .city(cityName)
                            .address(startingPointNameStr));
                    geoCoderEnd.setOnGetGeoCodeResultListener(new GeoCodeEndListener());
                    geoCoderEnd.geocode(new GeoCodeOption()
                            .city(cityName)
                            .address(endPointNameStr));
    ----------------------------------------------------------------------------------------------------------------------
    以下分别是监听
    /**
     * @title  地理编码监听-起点
     * @date   2017/11/21
     * @author 猫儿不吃鱼鱼
     */
    public class GeoCodeStartingListener implements OnGetGeoCoderResultListener {
    
        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
            if (geoCodeResult == null || geoCodeResult.error != SearchResult.ERRORNO.NO_ERROR) {
                Logger.v("没有结果");
                NavigationActivity.typeMap.put("starting",1);
                return;
            }
            NavigationActivity.typeMap.put("starting",2);
            NavigationActivity.naviMap.put("startingLongitude",geoCodeResult.getLocation().longitude);
            NavigationActivity.naviMap.put("startingLatitude",geoCodeResult.getLocation().latitude);
            Logger.v("起点地理编码经纬度:" + geoCodeResult.getLocation().longitude + "----" + geoCodeResult.getLocation().latitude);
            //获取地理编码结果
        }
    
        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
    
        }
    }
    
    
    /**
     * @title  地理编码监听-终点
     * @date   2017/11/21
     * @author 猫儿不吃鱼鱼
     */
    public class GeoCodeEndListener implements OnGetGeoCoderResultListener {
    
        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
            if (geoCodeResult == null || geoCodeResult.error != SearchResult.ERRORNO.NO_ERROR) {
                Logger.v("没有结果");
                NavigationActivity.typeMap.put("end",1);
                return;
            }
            NavigationActivity.typeMap.put("end",2);
            NavigationActivity.naviMap.put("endLongitude",geoCodeResult.getLocation().longitude);
            NavigationActivity.naviMap.put("endLatitude",geoCodeResult.getLocation().latitude);
        }
    
        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
    
        }
    }
    

    通过上面这段代码,我们已经把输入的起点和终点转换成了相对应的经纬度并且存进了对应的集合,我们现在就可以进行导航了:

                    /**
                     * 此处用延迟的目的:
                     * 因为上面在进行地理编码,是一个耗时操作,所以有可能下面调用路线规划导航的方法先执行
                     * 这样就会导致,第一次调用路线规划导航的方法所传进去的参数为空以及第一次导航之后新的起点和终点不能及时的传进去
                     * 所以加一个延时,保证不会出现以上两个问题
                     */
                    TimerTask task = new TimerTask() {
                        @Override
                        public void run() {
                            double startingType = typeMap.get("starting");
                            double endType = typeMap.get("end");
                            if(startingType == 1 || endType == 1){
                                showErrorToast("请更准确的输入起点和终点");
                            }else{
                                double startingLongitude = naviMap.get("startingLongitude");
                                double startingLatitude = naviMap.get("startingLatitude");
                                double endLongitude = naviMap.get("endLongitude");
                                double endLatitude = naviMap.get("endLatitude");
                                navigationUtil.routePlanToNavi(BNRoutePlanNode.CoordinateType.BD09LL,startingLongitude,
                                        startingLatitude,endLongitude,endLatitude,startingPointNameStr,endPointNameStr);
                            }
                        }
                    };
                    Timer timer = new Timer();
                    //4秒后执行TimeTask的run方法
                    timer.schedule(task, 4000);
    

    最后别忘记加上一个诱导页面的Activity类:

    /**
     * @title  百度导航诱导页面
     * @date   2017/11/21
     * @author 猫儿不吃鱼鱼
     */
    public class NavigationGuideActivity extends Activity implements NavigationRouteGuideModuleConstants,BNRouteGuideManager.OnNavigationListener {
    
        private Handler hd = null;
    
        /**
         * 算路节点
         */
        private BNRoutePlanNode mBNRoutePlanNode = null;
    
        /**
         * 百度导航通用模块
         */
        private BaiduNaviCommonModule mBaiduNaviCommonModule = null;
    
        /**
         * 是否使用通用接口
         * 对于导航模块有两种方式来实现发起导航。 1:使用通用接口来实现 2:使用传统接口来实现
         */
        private boolean useCommonInterface = true;
    
        /**
         * 信息显示
         */
        private static final int MSG_SHOW = 1;
    
        /**
         * 信息隐藏
         */
        private static final int MSG_HIDE = 2;
    
        /**
         * 信息复位节点
         */
        private static final int MSG_RESET_NODE = 3;
    
        /**
         * ret的通用模块
         */
        private final static String RET_COMMON_MODULE = "module.ret";
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            NavigationRoutePlanListener.activityList.add(this);
    
            createHandler();
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            }
            View view = null;
            if (useCommonInterface) {
                //使用通用接口
                mBaiduNaviCommonModule = NaviModuleFactory.getNaviModuleManager().getNaviCommonModule(
                        NaviModuleImpl.BNaviCommonModuleConstants.ROUTE_GUIDE_MODULE, this,
                        BNaviBaseCallbackModel.BNaviBaseCallbackConstants.CALLBACK_ROUTEGUIDE_TYPE, this);
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onCreate();
                    view = mBaiduNaviCommonModule.getView();
                }
            } else {
                //使用传统接口
                view = BNRouteGuideManager.getInstance().onCreate(this,this);
            }
    
            if (view != null) {
                setContentView(view);
            }
    
            Intent intent = getIntent();
            if (intent != null) {
                Bundle bundle = intent.getExtras();
                if (bundle != null) {
                    mBNRoutePlanNode = (BNRoutePlanNode) bundle.getSerializable(NavigationRoutePlanListener.ROUTE_PLAN_NODE);
                }
            }
            //显示自定义图标
            if (hd != null) {
                hd.sendEmptyMessageAtTime(MSG_SHOW, 5000);
            }
    
        }
    
        private void createHandler() {
            if (hd == null) {
                hd = new Handler(getMainLooper()) {
                    public void handleMessage(android.os.Message msg) {
                        if (msg.what == MSG_SHOW) {
                            addCustomizedLayerItems();
                        } else if (msg.what == MSG_HIDE) {
                            /**
                             * 导航过程管理类
                             * 获取BNRouteGuideManager实例
                             * 设置是否显示自定义图层
                             */
                            BNRouteGuideManager.getInstance().showCustomizedLayer(false);
                        } else if (msg.what == MSG_RESET_NODE) {
                            /**
                             * 导航中重新设置终点并直接算路导航
                             */
                            BNRouteGuideManager.getInstance().resetEndNodeInNavi(
                                    new BNRoutePlanNode(116.21142, 40.85087, "百度大厦11", null, BNRoutePlanNode.CoordinateType.GCJ02));
                        }
                    }
                };
            }
        }
    
        /**
         * 添加自定义图层项目
         */
        private void addCustomizedLayerItems() {
            //自定义图层元素类构造方法的集合
            List<BNRouteGuideManager.CustomizedLayerItem> items = new ArrayList<BNRouteGuideManager.CustomizedLayerItem>();
            BNRouteGuideManager.CustomizedLayerItem customizedLayerItem;
            if (mBNRoutePlanNode != null) {
                customizedLayerItem = new BNRouteGuideManager.CustomizedLayerItem(mBNRoutePlanNode.getLongitude(), mBNRoutePlanNode.getLatitude(),
                        mBNRoutePlanNode.getCoordinateType(), getResources().getDrawable(R.drawable.ic_launcher),
                        BNRouteGuideManager.CustomizedLayerItem.ALIGN_CENTER);
                items.add(customizedLayerItem);
    
                BNRouteGuideManager.getInstance().setCustomizedLayerItems(items);
            }
            BNRouteGuideManager.getInstance().showCustomizedLayer(true);
        }
    
        /**
         * 导航对应的生命周期管理
         */
        @Override
        protected void onStart() {
            super.onStart();
            // TODO Auto-generated method stub
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onStart();
                }
            } else {
                BNRouteGuideManager.getInstance().onStart();
            }
        }
    
        /**
         * 导航对应的生命周期管理
         */
        @Override
        protected void onResume() {
            super.onResume();
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onResume();
                }
            } else {
                BNRouteGuideManager.getInstance().onResume();
            }
        }
    
        /**
         * 导航对应的生命周期管理
         */
        @Override
        protected void onPause() {
            super.onPause();
    
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onPause();
                }
            } else {
                BNRouteGuideManager.getInstance().onPause();
            }
        }
    
        /**
         * 导航对应的生命周期管理
         */
        @Override
        protected void onStop() {
            super.onStop();
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onStop();
                }
            } else {
                BNRouteGuideManager.getInstance().onStop();
            }
        }
    
        /**
         * 导航对应的生命周期管理
         */
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onDestroy();
                }
            } else {
                BNRouteGuideManager.getInstance().onDestroy();
            }
            NavigationRoutePlanListener.activityList.remove(this);
        }
    
        /**
         * 配置改变设备信息
         * @param newConfig
         */
        public void onConfigurationChanged(android.content.res.Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onConfigurationChanged(newConfig);
                }
            } else {
                BNRouteGuideManager.getInstance().onConfigurationChanged(newConfig);
            }
        }
    
        /**
         * 导航过程监听器
         * 导航过程结束
         */
        @Override
        public void onNaviGuideEnd() {
            finish();
        }
    
        /**
         * 导航过程监听器
         * 通用动作回调接口,避免接口总是变动
         * @param actionType
         * @param arg1
         * @param arg2
         * @param obj
         */
        @Override
        public void notifyOtherAction(int actionType, int arg1, int arg2, Object obj) {
            if (actionType == 0) {
                //导航到达目的地 自动退出
                Logger.v("notifyOtherAction actionType = " + actionType + ",导航到达目的地!");
            }
            Logger.v("actionType:" + actionType + "arg1:" + arg1 + "arg2:" + arg2 + "obj:" + obj.toString());
        }
    
        /**
         * 键盘按键监听
         * @param keyCode
         * @param event
         * @return
         */
        @Override
        public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    Bundle mBundle = new Bundle();
                    mBundle.putInt(KEY_TYPE_KEYCODE, keyCode);
                    mBundle.putParcelable(KEY_TYPE_EVENT, event);
                    //设置模块的参数
                    mBaiduNaviCommonModule.setModuleParams(METHOD_TYPE_ON_KEY_DOWN, mBundle);
                    try {
                        Boolean ret = (Boolean)mBundle.get(RET_COMMON_MODULE);
                        if(ret) {
                            return true;
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }
            return super.onKeyDown(keyCode, event);
        }
    
        /**
         * 此处onBackPressed传递false表示强制退出,true表示返回上一级,非强制退出
         */
        @Override
        public void onBackPressed() {
            if(useCommonInterface) {
                if(mBaiduNaviCommonModule != null) {
                    mBaiduNaviCommonModule.onBackPressed(true);
                }
            } else {
                BNRouteGuideManager.getInstance().onBackPressed(false);
            }
        }
    
    }
    
    导航

    到此为止,整个百度导航就完全走通了,大家有没有实现功能呢?如果有问题或者不成功,请多看几遍文章或者留言。喜欢就赞个呗。

    相关文章

      网友评论

        本文标题:六、android百度地图之导航(终结篇)

        本文链接:https://www.haomeiwen.com/subject/nfcwvxtx.html