赞
踩
之前的文章总结了高德地图之拾取地点,接着在这个基础上继续总结了高德地图之路线规划,今天我们将在这个基础上来总结高德地图之实时导航。之前的文章如果没有看过的话,建议大家先了解一下,不然可能会看得不大懂。
其实实时导航相对来说应该是最简单的,但是API讲的不是很清楚,于是我将自己的弯路一一道来,让大家看看有没有什么收获。首先,我们按照官网API的说法来走一遍,简单来说就四步:
<?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>
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();
}
效果图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。