Android中集成高德地图SDK实现地图定位和导航功能(二)

我们接着上一篇文章开始继续实现android中集成高德地图的SDK实现地图 定位,搜索,导航的功能

如何让地图在手机上实现呢?

1.配置AndroidManifest 中的权限申请

可以参考官方文档

  <!--允许访问网络,必选权限-->
    <uses-permission android:name="android.permission.INTERNET" />

    <!--允许获取精确位置,实时导航为必选-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!--允许获取粗略位置,实时导航为必选-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!--允许获取设备和运营商信息,用于问题排查和网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <!--后台获取位置信息,若需后台定位或持续导航则必选-->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!--用于申请调用A-GPS模块,卫星定位加速-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

    <!--允许写入扩展存储,用于写入缓存定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!--用于用户链接蓝牙时,在导航组件页面的蓝牙连接提醒,建立链接后开发者可选用蓝牙通道进行tts播报-->
    <uses-permission android:name="android.permission.BLUETOOTH" />

    <!--用与导航状态中保持屏幕常亮-->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <!--允许写设备缓存,用于问题排查-->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <!--允许读设备等信息,用于问题排查-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

android6.0以后需要动态申请权限 这里我就不做详细解释了

设置高德地图的key

在androidMainfest文件的appliation 标签中添加之前在高的开发者平台上的key,代码如下

  <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="这个地方就是你之前申请的key" />

我的key是ba63b…
在这里插入图片描述

初始化地图控件

首先要先新创建一个承载地图的Activiy,然后初始化MapView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.GaodeMapActivity"
    android:orientation="vertical">
    
     <com.amap.api.maps.MapView
        android:id="@+id/gaode_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteX="16dp"
        tools:layout_editor_absoluteY="39dp">
     </com.amap.api.maps.MapView>

</LinearLayout>

然后再Activity中初始化地图空,这边需要了解到Activity生命周期和这个地图绑定到一起

public class GaodeMapActivity extends AppCompatActivity {
    
    
    private static final String TAG = "GaodeMapActivity";
    private MapView mapView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gaode_map);
        // 这一步操作就设置高德地图中的隐私合规,不然可能会出现地图无法正确加载的问题
        MapsInitializer.updatePrivacyShow(this,true,true);
        MapsInitializer.updatePrivacyAgree(this,true);
        //初始化地图控件
        mapView = (MapView) findViewById(R.id.gaode_map);
        //这个地方需要捕获下异常,不然会出现编译不过的情况
        try {
    
    
            mLocationClient = new AMapLocationClient(GaodeMapActivity.this);
        }catch (Exception e) {
    
    
         Log.e(TAG, e.getMessage());
        }
        mapView.onCreate(savedInstanceState);
        if (aMap == null) {
    
    
            //展示地图
            aMap = mapView.getMap();
            Log.i(TAG,"展示地图");
        }

       @Override
       protected void onDestroy() {
    
    
        super.onDestroy();
        mapView.onDestroy();
       }

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

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

      @Override
      public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
    
    
        super.onSaveInstanceState(outState, outPersistentState);
        //在activity保存时,同时也保存地图
        mapView.onSaveInstanceState(outState);
      }

在这里插入图片描述
效果如上图所示,这就完成了第一步地图的展示

2.定位蓝点

参考官方文档
完整的GaodeActivity的代码如下 因为是一个demo,所以代码写的比较潦草,多多担待

 private static final String TAG = "GaodeMapActivity";
    private MapView mapView;
    private AMap aMap = null;
    private double lat;
    private double lon;
    public AMapLocationClient mLocationClient = null;
    public AMapLocationClientOption mLocationOption = null;
    private Button btn_search;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gaode_map);
        btn_search = findViewById(R.id.btn_search);
        //这地方就是下面要讲的搜索导航功能
        btn_search.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(GaodeMapActivity.this, SearchActivity.class);
                startActivity(intent);
            }
        });
        MapsInitializer.updatePrivacyShow(this,true,true);
        MapsInitializer.updatePrivacyAgree(this,true);
        //初始化地图控件
        mapView = (MapView) findViewById(R.id.gaode_map);
        try {
    
    
            mLocationClient = new AMapLocationClient(GaodeMapActivity.this);
        }catch (Exception e) {
    
    
            Log.e(TAG, e.getMessage());
        }
        //设置定位回调监听
        mLocationClient.setLocationListener(mLocationListener);
        mapView.onCreate(savedInstanceState);
        if (aMap == null) {
    
    
            //展示地图
            aMap = mapView.getMap();
            Log.i(TAG,"展示地图");
        }
        MyLocationStyle myLocationStyle;
        myLocationStyle = new MyLocationStyle();
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE); //持续定位
        //设置连续定位模式下定位间隔
        myLocationStyle.interval(2000);
        myLocationStyle.strokeWidth(20f);
        aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
//aMap.getUiSettings().setMyLocationButtonEnabled(true);设置默认定位按钮是否显示,非必需设置。
        aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);
        myLocationStyle.showMyLocation(true);
    }

    public AMapLocationListener mLocationListener = new AMapLocationListener() {
    
    
        @Override
        public void onLocationChanged(AMapLocation amapLocation) {
    
    
            if (amapLocation != null) {
    
    
                if (amapLocation.getErrorCode() == 0) {
    
    
                    //定位成功回调信息,设置相关消息
                    amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
                    amapLocation.getLatitude();//获取纬度
                    amapLocation.getLongitude();//获取经度
                    amapLocation.getAccuracy();//获取精度信息
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date date = new Date(amapLocation.getTime());
                    df.format(date);//定位时间
                    amapLocation.getAddress();//地址,如果option中设置isNeedAddress为false,则没有此结果,网络定位结果中会有地址信息,GPS定位不返回地址信息。
                    amapLocation.getCountry();//国家信息
                    amapLocation.getProvince();//省信息
                    amapLocation.getCity();//城市信息
                    amapLocation.getDistrict();//城区信息
                    amapLocation.getStreet();//街道信息
                    amapLocation.getStreetNum();//街道门牌号信息
                    amapLocation.getCityCode();//城市编码
                    amapLocation.getAdCode();//地区编码
                    amapLocation.getAoiName();//获取当前定位点的AOI信息
                    lat = amapLocation.getLatitude();
                    lon = amapLocation.getLongitude();
                    Log.v("pcw","lat : "+lat+" lon : "+lon);

                    // 设置当前地图显示为当前位置
                    aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 15));
                    MarkerOptions markerOptions = new MarkerOptions();
                    markerOptions.position(new LatLng(lat, lon));
                    markerOptions.title("当前位置");
                    markerOptions.visible(true);
                    BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background));
                    markerOptions.icon(bitmapDescriptor);
                    aMap.addMarker(markerOptions);

                } else {
    
    
                    //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
                    Toast.makeText(GaodeMapActivity.this,
                            amapLocation.getErrorCode() + ", errInfo:"
                                    + amapLocation.getErrorInfo(), Toast.LENGTH_SHORT).show();
                }
            }
        }
    };


    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        mapView.onDestroy();
    }

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

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

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
    
    
        super.onSaveInstanceState(outState, outPersistentState);
        //在activity保存时,同时也保存地图
        mapView.onSaveInstanceState(outState);
    }

实现后的效果如下
在这里插入图片描述

3.实现搜索功能

1.首先我们要创建一个搜索的Activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.SearchActivity"
    android:orientation="vertical">

    <EditText
        android:id="@+id/search_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/search_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/search_edit"
        app:layout_constraintVertical_bias="1.0"
        tools:layout_editor_absoluteX="-51dp"
        />
</LinearLayout>

搜索item 的布局如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="18dp"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="城市"
        android:textSize="18sp"
        android:id="@+id/search_adapter_text"/>

</LinearLayout>

3.要有一个Adapter 来给Recyclerview展示数据

public class RvAdapter extends RecyclerView.Adapter<RvAdapter.ViewHolder> implements View.OnClickListener {
    
    
    private final ArrayList<Tip> list;
    private final Context context;
    private final  RecyclerView rv;
    private OnItemClickListener  mOnItemClickListener;

    public RvAdapter(ArrayList<Tip> list, Context context, RecyclerView rv) {
    
    
        this.list = list;
        this.context = context;
        this.rv = rv;
    }

    @Override
    public void onClick(View view) {
    
    
        int position = rv.getChildAdapterPosition(view);

        //程序执行到此,会去执行具体实现的onItemClick()方法
        if (mOnItemClickListener != null) {
    
    
           mOnItemClickListener.onItemClick(rv, view, position, list.get(position));
            Log.i("TAG", "onClick: "+position);
        }
    }

    public interface  OnItemClickListener{
    
    
        void onItemClick(RecyclerView recyclerView,View view, int position,Tip data);
    }
    public void setmOnItemClickListener(OnItemClickListener  clickListener) {
    
    
        this.mOnItemClickListener = clickListener;
    }

    public void setData(List<Tip> list) {
    
    
        if (list != null) {
    
    
            this.list.clear();
            this.list.addAll(list);
            notifyDataSetChanged();
            Log.i("TAG", "setData: "+ list);
        }
    }

    @Override
    public RvAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        //View view = LayoutInflater.from(context).inflate(R.layout.search_item, parent ,false);
        View view = View.inflate(context, R.layout.search_item, null);
        view.setOnClickListener(this);
        return new ViewHolder(view);
    }


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
        Tip tip = list.get(position);
        holder.textView.setText(tip.getName());
        Log.i("TAG", "onBindViewHolder:  getName= "+tip.getName());
    }

    @Override
    public int getItemCount() {
    
    
        return list.size();
    }
     static class ViewHolder extends RecyclerView.ViewHolder{
    
    
       private TextView textView;
        public ViewHolder(@NonNull View itemView) {
    
    
            super(itemView);
            textView = itemView.findViewById(R.id.search_adapter_text);
        }
    }

4.下面就是SearchActivty 的代码

public class SearchActivity extends AppCompatActivity implements Inputtips.InputtipsListener, TextWatcher,RvAdapter.OnItemClickListener {
    
    
   private RvAdapter rvAdapter;
   private Inputtips inputtips;
   private AMapNavi aMapNavi;
   private EditText editText;
   private RecyclerView recyclerView;
   private ArrayList<Tip> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        editText = findViewById(R.id.search_edit);
        editText.addTextChangedListener(this);
        recyclerView = (RecyclerView) findViewById(R.id.search_rv);
        LinearLayoutManager layoutManager = new LinearLayoutManager(SearchActivity.this, RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        rvAdapter = new RvAdapter(list,SearchActivity.this,recyclerView);
        rvAdapter.setmOnItemClickListener(this);
        recyclerView.setAdapter(rvAdapter);
        inputtips = new Inputtips(this,(InputtipsQuery) null);
        inputtips.setInputtipsListener(this);
    }



    @Override
    public void onGetInputtips(List<Tip> list, int i) {
    
    
        Log.i("Tag","onGetInputtips data = "+list);
        rvAdapter.setData(list);
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    
     InputtipsQuery inputtipsQuery = new InputtipsQuery(String.valueOf(charSequence),null);
     inputtipsQuery.setCityLimit(true);
     inputtips.setQuery(inputtipsQuery);
     inputtips.requestInputtipsAsyn();
    }

    @Override
    public void afterTextChanged(Editable editable) {
    
    

    }
    @Override
    public void onItemClick(RecyclerView parent, View view, int postion, Tip data) {
    
    
      
    }

这就完成了搜索功能,效果如下图

在这里插入图片描述

4.导航功能

官方文档参考
1.我们需要通过AmapNaviPage来启动,他是一个单例模式

        //导航参数对象(起点,途径,终点,导航方式)DRIVER是导航方式(驾驶,步行...当前为驾驶)ROUTE会计算路程选择
        AmapNaviParams params = new AmapNaviParams(null, null, poi, AmapNaviType.DRIVER, AmapPageType.ROUTE);
        //传递上下文和导航参数
        AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);

2.声明定位 service 组件需在 AndroidManifest.xml 中声明定位 service 组件。请在application标签中声明service 组件,添加如下代码:

<service android:name="com.amap.api.location.APSService"/>

3.还要再AndroidMainfest 中声明导航组件的Activity

<activity
            android:name="com.amap.api.navi.AmapRouteActivity"
            android:theme="@android:style/Theme.NoTitleBar"
            android:configChanges="orientation|keyboardHidden|screenSize|navigation" />

然后附上完整的SearchActivity的代码

public class SearchActivity extends AppCompatActivity implements Inputtips.InputtipsListener, TextWatcher,RvAdapter.OnItemClickListener {
    
    
   private RvAdapter rvAdapter;
   private Inputtips inputtips;
   private AMapNavi aMapNavi;
   private EditText editText;
   private RecyclerView recyclerView;
   private ArrayList<Tip> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        editText = findViewById(R.id.search_edit);
        editText.addTextChangedListener(this);
        recyclerView = (RecyclerView) findViewById(R.id.search_rv);
        LinearLayoutManager layoutManager = new LinearLayoutManager(SearchActivity.this, RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        rvAdapter = new RvAdapter(list,SearchActivity.this,recyclerView);
        rvAdapter.setmOnItemClickListener(this);
        recyclerView.setAdapter(rvAdapter);
        inputtips = new Inputtips(this,(InputtipsQuery) null);
        inputtips.setInputtipsListener(this);
        //这是隐私合规接口,如果不加,可能出现地图加载不出来的问题
        NaviSetting.updatePrivacyShow(this, true, true);
        NaviSetting.updatePrivacyAgree(this, true);
        try {
    
    
             //这个地方也许捕获一下异常,不然编译不过去
            aMapNavi = AMapNavi.getInstance(this);
        }catch (Exception e){
    
    
            Log.e("TAG", e.getMessage());
        }
         if (aMapNavi!=null) {
    
    
             //设置内置语音播报
             aMapNavi.setUseInnerVoice(true, false);
         }
    }



    @Override
    public void onGetInputtips(List<Tip> list, int i) {
    
    
        Log.i("Tag","onGetInputtips data = "+list);
        rvAdapter.setData(list);
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    
     InputtipsQuery inputtipsQuery = new InputtipsQuery(String.valueOf(charSequence),null);
     inputtipsQuery.setCityLimit(true);
     inputtips.setQuery(inputtipsQuery);
     inputtips.requestInputtipsAsyn();
    }

    @Override
    public void afterTextChanged(Editable editable) {
    
    

    }
    @Override
    public void onItemClick(RecyclerView parent, View view, int postion, Tip data) {
    
    
        Log.i("TAG", "onItemClick:  点击了"+postion+"条");
        //得到点击的坐标
        LatLonPoint point = data.getPoint();
        Log.i("Tag", "坐标为"+point);
        //得到经纬度
        Poi poi = new Poi(data.getName(), new LatLng(point.getLatitude(), point.getLongitude()), data.getPoiID());
        //导航参数对象(起点,途径,终点,导航方式)DRIVER是导航方式(驾驶,步行...当前为驾驶)ROUTE会计算路程选择
        AmapNaviParams params = new AmapNaviParams(null, null, poi, AmapNaviType.DRIVER, AmapPageType.ROUTE);
        //传递上下文和导航参数
        AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);
    }
}

下面附上实现效果图
在这里插入图片描述
这个地方还要插一句 需要在AndroidMainfest 的 applcation 中添加 这样一段代码不然会点击开始导航会出现奔溃 详情请参考 为啥要添加下面的代码

android:allowNativeHeapPointerTagging="false"

这就是以上所有的内容,如有前期准备工作搞不定的请参考我的上一篇:Android中集成高德地图SDK实现地图定位和导航功能(一)

猜你喜欢

转载自blog.csdn.net/Qinbenjiaren/article/details/130743437