高德地图之实时导航

之前的文章总结了高德地图之拾取地点,接着在这个基础上继续总结了高德地图之路线规划,今天我们将在这个基础上来总结高德地图之实时导航。之前的文章如果没有看过的话,建议大家先了解一下,不然可能会看得不大懂。
其实实时导航相对来说应该是最简单的,但是API讲的不是很清楚,于是我将自己的弯路一一道来,让大家看看有没有什么收获。首先,我们按照官网API的说法来走一遍,简单来说就四步:

  • 定义AMapNaviView实现
    简单来说就是声明一个控件,这个控件和前文的地图不是一个包了,代码如下:
  • AMapNaviView 的生命周期
    无非就是维护生命周期,并且同路线规划一样实现导航视图事件监听接口——AMapNaviViewListener,代码如下:
  • 进行路线规划
    这里就一句话“具体参考:驾车路径规划或步行路径规划。”也就是说我们直接使用上文的路线规划就好了。这里有一个大坑,后文会提到。
  • 开启导航
    这个最简单,就是在第二步实现接口的时候,重写 onCalculateRouteSuccess()函数即可。
定义AMapNaviView实现
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- 实时导航的地图控件 -->
    <!--<com.amap.api.maps.MapView-->
        <!--android:id="@+id/navi_view"-->
        <!--android:layout_width="match_parent"-->
        <!--android:layout_height="0dp"-->
        <!--android:layout_weight="1"/>-->

    <com.amap.api.navi.AMapNaviView
        android:id="@+id/navi_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>
AMapNaviView 的生命周期
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //获取 AMapNaviView 实例
    mAMapNaviView = (AMapNaviView) findViewById(R.id.navi_view);
    mAMapNaviView.setAMapNaviViewListener(this);

}

@Override
protected void onResume() {
    super.onResume();
    mAMapNaviView.onResume();
}

@Override
protected void onPause() {
    super.onPause();
    mAMapNaviView.onPause();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mAMapNaviView.onDestroy();
}
开启导航
@Override
public void onCalculateRouteSuccess() {
    super.onCalculateRouteSuccess();
    mAMapNavi.startNavi(NaviType.GPS);
}

上面提到这里有一个bug,就是说当我们有多条线路的时候,我们怎么指定线路呢?而且就算只有一条线路,这里也不能实现导航。这个时候实时导航如下:

这里写图片描述

当时我很奇怪,因为demo里并没有发现路线规划的Activity是如何将路线,以及起点、终点传到实时导航的Activity,后来我发现在路线规划Activity的时候有一个亮点:

mAMapNavi = AMapNavi.getInstance(getApplicationContext());

导航对外控制类对象mAMapNavi其实是一个单例,我们看看实时导航里面是怎样获取这个对象的?

 //实时导航获取AMapNavi实例
 mAMapNavi = AMapNavi.getInstance(this);
 //demo中获取AMapNavi实例
 //com.amap.navi.demo.activity.RouteNaviActivity
 mAMapNavi = AMapNavi.getInstance(getApplicationContext());

虽然我们传入了不同的Context对象,但是其实效果都一样,我们看看AMapNavi源码中getInstance(Context var0)是怎么实现单例的?

public static synchronized AMapNavi getInstance(Context var0) {
        try {
            if(singletonAMapNavi == null) {
                singletonAMapNavi = new AMapNavi(var0);
            }
        } catch (Throwable var2) {
            du.a(var2);
            ey.b(var2, "AMapNavi", "getInstance(Context context)");
        }

        return singletonAMapNavi;
    }

解决了起点、终点的传递,但是线路好像还没有解决指定线路的值!这个值其实也是在路线规划Activity中我们已实现了,看看当多条线路的时候我们点击其中一条线路的事件监听,代码如下:

holder.getView(ll_itemview).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        currentPosition = position;
                        //已经选中,再次选中直接返回
                        if(lastPosition==currentPosition){
                            return;
                        }else{
                            //当前的下标值赋值给当前选择的线路下标值
                            routeIndex = position;
                            //更换线路
                            changeRoute();
                            //选择Item设置背景
                            selectedBackground(holder);
                            //清空上次设置的背景
                            cleanSelector();
                        }
                        lastPosition = position;
                    }

                });
    /**
     * 选择路线
     */
    public void changeRoute() {

        //计算出来的路径只有一条
        if (routeOverlays.size() == 1) {
            //必须告诉AMapNavi 你最后选择的哪条路
            mAMapNavi.selectRouteId(routeOverlays.keyAt(0));
            return;
        }

        if (routeIndex >= routeOverlays.size())
            routeIndex = 0;
        //根据选中的路线下标值得到路线ID
        int routeID = routeOverlays.keyAt(routeIndex);
        //突出选择的那条路
        for (int i = 0; i < routeOverlays.size(); i++) {
            int key = routeOverlays.keyAt(i);
            routeOverlays.get(key).setTransparency(0.4f);
        }
        routeOverlays.get(routeID).setTransparency(1);
        /**把用户选择的那条路的权值弄高,使路线高亮显示的同时,重合路段不会变的透明**/
        routeOverlays.get(routeID).setZindex(zindex++);

        //必须告诉AMapNavi 你最后选择的哪条路
        mAMapNavi.selectRouteId(routeID);
        routeIndex++;

    }

我们看到上面代码中的mAMapNavi.selectRouteId(int id)方法就设置过了,所以我们在实时导航里面,已经不用再次规划路线,可以直接启动导航,这里我们直接看onCreate(Bundle savedInstanceState) 方法的源码就好:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        ActionBar actionbar = getSupportActionBar();
        if(actionbar!=null){
            actionbar.hide();
        }
        setContentView(R.layout.activity_gpsnavi);
        //定义AMapNaviView实现 
        mAMapNaviView = (AMapNaviView) findViewById(R.id.navi_view);
        mAMapNaviView.onCreate(savedInstanceState);
        mAMapNaviView.setAMapNaviViewListener(this);
        //获取AMapNavi实例
        mAMapNavi = AMapNavi.getInstance(this);
        //添加监听回调,用于处理导航视图事件监听。
        mAMapNavi.addAMapNaviListener(this);
        //初始化语音引擎
        mTtsManager = TTSController.getInstance(getApplicationContext());
        //实例化语音引擎
        mTtsManager.init();
        //添加导航事件监听。(关键是语音的播放)
        mAMapNavi.addAMapNaviListener(mTtsManager);
        //启动实时导航
        mAMapNavi.startNavi(NaviType.GPS);
        //启动模拟导航
        //mAMapNavi.startNavi(NaviType.EMULATOR);

    }

这里写图片描述
上面已经解决了实时导航、语音播放(建议自己申请一个ID),但是最后还有一个坑——就是我们的Activity退回到路线规划Activity的时候,再次规划路线就会失败,就算再次初始化也会失败,不信邪的话可以尝试,那么我们需要怎么解决呢?先看看效果图:

这里写图片描述

大家应该看到左下角的“X”图标,当我们点击这个图标的时候,会有两种情况,要么就是弹起来一个SDK包含的Dialog,要么就是自定义一个事件,但是不管是哪一种,总应该重写事件监听方法,对吧?

@Override
 public boolean onNaviBackClick() {
//导航页面左下角返回按钮的回调接口 
//  false-由SDK主动弹出『退出导航』对话框,
//  true-SDK不主动弹出『退出导航对话框』,由用户自定义

     return false;
 }

@Override
    public void onNaviCancel() {
//导航页面左下角返回按钮点击后弹出的『退出导航对话框』中选择『确定』后的回调接口。
        finish();
    }

这里写图片描述

上面代码对该Activity调用了finish()方法,这个时候Activity执行onDestroy()方法的时候,根据上面生命周期的维护,会将AMapNavi对象给销毁掉,导致退回到路线规划Activity的时候AMapNavi对象不能用。
因此我们修改onDestroy()方法即可:

@Override
    protected void onDestroy() {
        super.onDestroy();
        mAMapNavi.stopNavi();
        mTtsManager.destroy();
    }

效果图:

这里写图片描述

详见源码

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页