《第一行代码》11 百度地图实战

个人笔记,仅供参考

《第一行代码》11 百度地图实战_第1张图片
目录

1 (LBS)位置服务简介

基于位置的服务,简称 LBS (Location Based Service)
主要工作原理是利用无线电通讯网络或GPS等定位方式来确定移动设备所在位置

即我们通常所说的定位,分两种方式:
一种是通过GPS来定位
基于手机内置的GPS硬件直接和卫星交互来获取当前的经纬度信息,这种定位方式精确度非常高,缺点是只能在室外使用,室内基本上无法接收到卫星的信号
另外一种是通过网络来定位
其工作原理是根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站的距离,再通过三角定位确定出一个大概的位置,这种定位方式精确度一般,优点是室内室外都可以使用

Android API 其实已经对这两种定位做了支持,但是由于某些原因,Google服务在国内无法访问

因此我们只能用到国内第三方公司的SDK
也是主流的两种: 百度地图 和 高德地图
我们就从百度地图开始吧!

2 注册成为百度地图开发者

  • 如果以前没百度账号就注册一个
  • 如果之前就有则登陆即可 ,百度系的产品账号大部分都是可以通用的
    官网地址:https://lbsyun.baidu.com/
  • 首页进控制台,然后注册成为开发者
《第一行代码》11 百度地图实战_第2张图片
《第一行代码》11 百度地图实战_第3张图片
  • 注册完以后,可以再回到控制台,你会发现上图左边有个创建应用
    没错,我们接下来就开始创建应用
    配置并拿到专属于你自己的 API Key
《第一行代码》11 百度地图实战_第4张图片
  • 以我之前使用过的应用来讲
    应用名称: 你可以自定义,比如我这里就叫 MyBaiDuMapDemo
    应用类型:点击下拉菜单改为 Android SDK
    启动服务:默认不变全选
    发布版SHA1: 我这里处于自己测试,发布和开发都用的一个SHA1,如果是正式上线项目,发布版的值允许和开发环境不一样(还请自行网上搜索怎么拿)
    开发版SHA1:它是指打包程序时所用签名文件的 SHA1 指纹
    马上会讲到怎么拿这个值
    包名:即你的项目的包名要和这里一致
    《第一行代码》11 百度地图实战_第5张图片

OK,马上讲一下这个 开发版SHA1怎么拿

  • 开始新建项目吧!新建一个名为 BaiDuMapDemo的 Module
  • 找到 右侧 Gradle -> 你的项目BaiDuMapDemo -> android -> signingReport 并双击,查看签名信息
《第一行代码》11 百度地图实战_第6张图片
  • 稍等片刻就会在底部AndroidStudio控制台显示出来你的 SHA1值
《第一行代码》11 百度地图实战_第7张图片
  • 最后,回到之前创建应用的界面,填入 SHA1值,点击提交,创建成功!
《第一行代码》11 百度地图实战_第8张图片
  • 那个AK值 bgguVrsdis1ZeNQccqnZXSzP8tN2kYOn就是我们的API Key
    等下需要在项目中用到
    现在,我们就可以正式开始百度地图的开发了!

3 SDK下载配置

先下载需要的SDK
由于等下要用到了定位,就先从首页进入定位SDK看看,当然选地图也可以,随便进一个

《第一行代码》11 百度地图实战_第9张图片
  • 然后会跳到该SDK的详细界面
    可以看到,官方文档的 获取密钥、开发指南、类参考都很详细
    感兴趣的可以自行深入学习
    不过我们点 相关下载,去下载SDK,然后在新的网页点击 去下载
《第一行代码》11 百度地图实战_第10张图片

《第一行代码》11 百度地图实战_第11张图片
  • 折腾了半天才到真正下载界面,我勒个去
    选中 基础定位 和 基础地图,然后点击下面的下载按钮
    《第一行代码》11 百度地图实战_第12张图片

下载后会拿到以下几个文件:
BaiduLBS_Android.jar是Java层需要用到的
其他文件是Native层要用到的
文件夹点进去会看到一些 so文件
so文件是用C/C++语言进行编写,然后再用NDK编译出来的
当然百度都已经帮我们封装好了,我们只需要关心怎么使用就行

《第一行代码》11 百度地图实战_第13张图片
  • 在AndroidStudio中把我们的项目切换到project视图下
    再把下载的 jar包 复制进项目的libs 文件夹下
    然后在main目录下新建一个与java文件夹同级的Directory目录jniLibs
    把下载的其余5个文件夹复制进去
    《第一行代码》11 百度地图实战_第14张图片
  • 由于每个新创建的项目中,build/gradle里都会有这一句
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    它表示把 libs 目录下所有的 jar包文件添加到当前项目的引用中
  • 因此我们只需要再次Sync同步一下即可,让刚才复制jar文件生效

4 使用百度定位

4-1 显示经纬度

  • 终于开始写代码部分了,说不多说
    先从布局开始,简单放个TextView


    

  • 在配置文件中
    先在里加入一个标签
    name值是固定的
    value填入我们之前网站上创建应用生成的API key
    然后再注册一个SDK的服务Service,固定写法不变
    (至于名字以.f结尾,是因为内部已经混淆过了)
    最后把百度地图用到的一些必要权限加上
    
        
        
        
            
                
                
            
        

        
    

    
    
    
    
    
    
    
    
    
    
  • 再看MainActivity代码
package com.example.kt.baidumapdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient;
    private TextView positionText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        setContentView(R.layout.activity_main);
        positionText = findViewById(R.id.position_text_view);
        //6.0权限
        List permissionList = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        //集合不为空则代表有需要申请的危险权限
        if (!permissionList.isEmpty()) {
            String[] permissions = permissionList.toArray(new String[permissionList.size()]);
            ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
        } else {
            requestLocation();
        }
    }


    private void requestLocation() {
        mLocationClient.start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_SHORT).show();
                        }
                        finish();
                        return;
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            StringBuilder currentPosition = new StringBuilder();
            currentPosition.append("纬度:").append(location.getLatitude())
                    .append("\n");
            currentPosition.append("经度:").append(location.getLongitude())
                    .append("\n");

            currentPosition.append("定位方式:");
            if (location.getLocType() == BDLocation.TypeGpsLocation) {
                currentPosition.append("GPS");
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
                currentPosition.append("网络");
            }
            positionText.setText(currentPosition);
        }
    }
}


  • OnCreate()方法中
    我们首先创建了 LocationClient 实例,参数为Context
    然后调用registerLocationListener()方法注册了一个定位监听器
    当获取到位置信息的时候,会回调这个定位监听器
  • 由于android 6.0运行时权限,所以要加上动态申请权限的代码
    其中有三个属于危险权限
    ACCESS_FINE_LOCATION
    READ_PHONE_STATE
    WRITE_EXTERNAL_STORAGE
    我们需要一次性申请三个权限
  • 这里我们用到一个做法,首先创建一个空的List集合,然后判断这3个权限是否被授权,如果没有被授权就添加到集合中,如果已经授权则不添加
    然后判断List里是否有对象,有则代表需要动态申请权限
    调用toArray()方法将List转换成数组
    然后传入到ActivityCompat.requestPermissions()一次性全部去申请
  • 再来看onRequestPermissionsResult()方法
    这里通过一个循环将申请的每个权限都进行了判断,如果有任何一个权限被拒绝,则调用finish()销毁当前界面
    只有当全部权限被授权,才会调用requestLocation()开始位置定位
  • requestLocation()中调用 LocationClient 的start()即可开始定位
  • 定位的结果会回调到我们前面注册的监听器 MyLocationListener 当中
    可以看到在 onReceiveLocation()方法中
    通过 BDLocation 的 getLatitude()拿到了纬度
    通过getLongitude()拿到了经度
    通过getLocType()拿到了定位方式
    最后显示出来

运行效果:


4-2 实时更新位置

  • 在默认情况下,调用 LocationClient 的start()只会定位一次
  • 由于我们想要在移动的过程中,实时更新位置
    因此在requestLocation()方法前新增一个initLocation()方法
    private void requestLocation() {
        initLocation(); //新增
        mLocationClient.start();
    }
  • 观察initLocation()方法
    //新增
    private void initLocation(){  
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        mLocationClient.setLocOption(option);
    }

    //新增
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();
    }

  • 我们创建了一个 LocationClientOption 对象
    调用它的setScanSpan()可以设置每次更新位置间隔时间
    这里设为了每5秒更新一次
    然后调用 LocationClient 的 setLocOption()方法,并传入LocationClientOption 对象,这样就可以了
  • 然后在活动被销毁的时候,记得调用 LocationClient 的stop()来停止定位
    否则程序会在后台持续不断地定位,消耗手机电量

运行效果:
现在重新运行一遍程序,拿着手机到处移动,会发现经纬度信息也会跟着一起变化

4-3 选择定位模式

  • 我们一直使用的 "网络定位"
    如果需要使用GPS定位,则需要用户手动去设置启动


    《第一行代码》11 百度地图实战_第15张图片
  • 高精度模式:允许用户使用 GPS 、无线网络、蓝牙、移动网络来进行定位
    节电模式:只允许用户使用 无线网络、蓝牙、移动网络来进行定位
    仅限设备模式:只允许用户使用 GPS
    所以我们如果要切换到GPS,则选择 高精度模式仅限设备模式
  • 开启了GPS定位以后
    我们还可以对百度SDK的定位模式进行指定,共有3种:
    High_Accuracy
    表示高精度模式,在GPS信号正常的情况下优先使用GPS,在无法接收GPS的时候使用网络定位,一般手机默认就是这种模式
    Battery_Saving
    表示节电模式,只会使用网络定位
    Device_Sensors
    表示传感器模式,只会使用GPS定位
  • 修改 initLocation()方法,指定为传感器模式,走出去,即可切换到GPS定位
    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        //新增
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        mLocationClient.setLocOption(option);
    }

4-4 具体位置信息

  • 仍然是修改 initLocation()方法
    加入setIsNeedAddress(),传入 true 代表需要获取当前位置的详细信息
    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        //新增
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }
  • 然后修改 MyLocationListener
    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            StringBuilder currentPosition = new StringBuilder();
            currentPosition.append("纬度:").append(location.getLatitude())
                    .append("\n");
            currentPosition.append("经度:").append(location.getLongitude())
                    .append("\n");
            //新增
            currentPosition.append("省:").append(location.getProvince())
                    .append("\n");
            currentPosition.append("市:").append(location.getCity())
                    .append("\n");
            currentPosition.append("区:").append(location.getDistrict())
                    .append("\n");
            currentPosition.append("街道:").append(location.getStreet())
                    .append("\n");

            currentPosition.append("定位方式:");
            if (location.getLocType() == BDLocation.TypeGpsLocation) {
                currentPosition.append("GPS");
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
                currentPosition.append("网络");
            }
            positionText.setText(currentPosition);
        }
    }

  • 这里就比较简单
    通过 BDLocation 的 getProvince()拿到省、getCity()拿到市、getDistrict()拿到区、getStreet()拿到街道等信息

重新运行遍看下效果:


《第一行代码》11 百度地图实战_第16张图片

OK,定位这一块基本就到此为止
更加进阶的用法还请自行参考官方文档或者其他博客

5 使用百度地图

5-1 显示地图

  • 还是接上面的例子
    先来看布局文件,把之前的TextView隐藏,放一个百度地图自带的控件MapView进去


    
    

  • 再来看MainActivity代码
package com.example.kt.baidumapdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.MapView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient;
    private TextView positionText;
    private MapView mapView; //新增

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        SDKInitializer.initialize(getApplicationContext()); //新增
        setContentView(R.layout.activity_main);
        positionText = findViewById(R.id.position_text_view);
        mapView = findViewById(R.id.bmapView); //新增
        //6.0权限
        List permissionList = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        //集合不为空则代表有需要申请的危险权限
        if (!permissionList.isEmpty()) {
            String[] permissions = permissionList.toArray(new String[permissionList.size()]);
            ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
        } else {
            requestLocation();
        }
    }


    private void requestLocation() {
        initLocation();
        mLocationClient.start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_SHORT).show();
                        }
                        finish();
                        return;
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            StringBuilder currentPosition = new StringBuilder();
            currentPosition.append("纬度:").append(location.getLatitude())
                    .append("\n");
            currentPosition.append("经度:").append(location.getLongitude())
                    .append("\n");
            currentPosition.append("省:").append(location.getProvince())
                    .append("\n");
            currentPosition.append("市:").append(location.getCity())
                    .append("\n");
            currentPosition.append("区:").append(location.getDistrict())
                    .append("\n");
            currentPosition.append("街道:").append(location.getStreet())
                    .append("\n");


            currentPosition.append("定位方式:");
            if (location.getLocType() == BDLocation.TypeGpsLocation) {
                currentPosition.append("GPS");
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
                currentPosition.append("网络");
            }
            positionText.setText(currentPosition);
        }
    }

    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

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

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();
        //新增
        mapView.onDestroy();
    }
}
  • 注意新增的部分代码
    首先需要在setContentView()之前
    调用SDKInitializer.initialize(getApplicationContext());进行初始化
    然后找到 MapView 的实例,后面要用到
    最后在onResume()onPause()onDestroy()这3个方法里对mapView进行管理,以便资源及时得到释放

重新运行一下程序:


《第一行代码》11 百度地图实战_第17张图片

5-2 移动到我的位置

  • 可以看见地图是显示出来了,默认是北京市,但是应该根据定位,显示在我的位置
  • 话不多说,直接在MainActivity加入以下代码
package com.example.kt.baidumapdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient;
    private TextView positionText;
    private MapView mapView;
    private BaiduMap baiduMap; //新增
    private boolean isFirstLocate = true; //新增

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);
        positionText = findViewById(R.id.position_text_view);
        mapView = findViewById(R.id.bmapView);
        baiduMap = mapView.getMap(); //新增
        //6.0权限
        List permissionList = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        //集合不为空则代表有需要申请的危险权限
        if (!permissionList.isEmpty()) {
            String[] permissions = permissionList.toArray(new String[permissionList.size()]);
            ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
        } else {
            requestLocation();
        }
    }


    private void requestLocation() {
        initLocation();
        mLocationClient.start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_SHORT).show();
                        }
                        finish();
                        return;
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            //新增
            if(location.getLocType() == BDLocation.TypeGpsLocation
                    || location.getLocType() == BDLocation.TypeNetWorkLocation){
                navigateTo(location);
            }
        }
    }

    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

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

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

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

    //新增
    private void navigateTo(BDLocation location){
        if(isFirstLocate){
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
            MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
            baiduMap.animateMapStatus(update);
            update = MapStatusUpdateFactory.zoomTo(16f);
            baiduMap.animateMapStatus(update);
            isFirstLocate = false;
        }
    }
}
  • 先是通过 mapView.getMap()拿到一个 BaiduMap 的实例
    百度LBS SDK 提供了这个 BaiduMap 类,它是地图的总控制器,有了BaiduMap 实例后就可以进行各种操作,比如设置地图缩放级别、将地图移动到某个经纬度上
  • 当位置移动的时候,会调用 MyLocationListener 的onReceiveLocation()方法
    接着新建一个navigateTo()方法
    我们直接把 BDLocation 对象传给 navigateTo()方法
  • 我们重点来看navigateTo()方法
    首先借助 LatLng 类,创建一个实例,并传入纬度、经度作为参数
    接着调用 MapStatusUpdateFactory.newLatLng()方法,并将LatLng实例传入,得到一个 MapStatusUpdate 对象
    然后把这个对象传入到 BaiduMap 的 animateMapStatus()方法中
    这样就会将地图移动到当前经纬度位置
  • 百度地图将缩放级别范围限定在 3 到 19之间,小数点也可以取,值越大,越精细
    通过MapStatusUpdateFactory.zoomTo()方法传入一个float常量作为缩放级别,同样会得到一个MapStatusUpdate 对象
    我们再次把这个对象传入到 BaiduMap 的 animateMapStatus()方法中
    这样就完成了地图缩放级别的设置
  • 最后我们是加了一个boolean变量 isFirstLocate 来控制
    为了是防止多次加载 animateMapStatus()方法
    因为将地图移动到当前位置,只需要在第一次定位的时候调用一次就可以了

运行效果:


《第一行代码》11 百度地图实战_第18张图片

5-3 显示位置光标在地图上

  • 在MainActivity加入以下代码
package com.example.kt.baidumapdemo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient;
    private TextView positionText;
    private MapView mapView;
    private BaiduMap baiduMap;
    private boolean isFirstLocate = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);
        positionText = findViewById(R.id.position_text_view);
        mapView = findViewById(R.id.bmapView);
        baiduMap = mapView.getMap();
        baiduMap.setMyLocationEnabled(true);//新增
        //6.0权限
        List permissionList = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        //集合不为空则代表有需要申请的危险权限
        if (!permissionList.isEmpty()) {
            String[] permissions = permissionList.toArray(new String[permissionList.size()]);
            ActivityCompat.requestPermissions(MainActivity.this, permissions, 1);
        } else {
            requestLocation();
        }
    }

    private void requestLocation() {
        initLocation();
        mLocationClient.start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序", Toast.LENGTH_SHORT).show();
                        }
                        finish();
                        return;
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            if(location.getLocType() == BDLocation.TypeGpsLocation
                    || location.getLocType() == BDLocation.TypeNetWorkLocation){
                navigateTo(location);
            }
        }
    }

    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

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

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();
        mapView.onDestroy();
        baiduMap.setMyLocationEnabled(false);//新增
    }

    private void navigateTo(BDLocation location){
        if(isFirstLocate){
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
            MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
            baiduMap.animateMapStatus(update);
            update = MapStatusUpdateFactory.zoomTo(16f);
            baiduMap.animateMapStatus(update);
            isFirstLocate = false;
        }
        //新增
        MyLocationData.Builder builder = new MyLocationData.Builder();
        builder.latitude(location.getLatitude());
        builder.longitude(location.getLongitude());
        MyLocationData locationData = builder.build();
        baiduMap.setMyLocationData(locationData);
    }
}

  • 先在 onCreate()onDestroy()里分别调用 MapView 的
    setMyLocationEnabled()把显示位置的功能 打开 和 关闭
  • 然后来到 navigateTo()方法中
    百度LBS SDK中提供了一个 MyLocationData.Builder类,用来封装设备当前所在位置,我们只需传入经纬度即可
    当把封装的信息都设置完以后
    调用 MyLocationData.Builder 的 build()方法得到一个 MyLocationData 类实例
    最后再将这个实例传入到 BaiduMap的 setMyLocationData()方法中即可
    这样就可以让设备显示在地图上了
  • 注意:
    这部分代码写在了 isFirstLocate这个if条件语句外
    因为让地图移动到我们当前位置,只需要定位在第一次定位的时候执行就可以了
    但是设备在地图上显示的问题却是跟随设备移动而实时改变的

最后,重新运行一下程序,可以看到一个蓝色小圆点来代表了当前的位置

《第一行代码》11 百度地图实战_第19张图片

6 出现过的一些问题

问题一:百度定位,返回经纬度都是4.9E-324

  • 第一次用的时候急急躁躁,运行一下定位,我了个去,经纬度一样,还是这种奇怪数据,什么情况?
  • 打个断点看了一下
    返回信息中报错:
    NetWork location failed because baidu location service can not decrypt the request query, please check the so file !
我的情况:
  • 查看了一下报错信息,有的说是so文件没加载,还有一些其他说法
    我仔细检查了一下步骤是不是哪里出了问题
    原来我毛毛躁躁,把 jnilibs文件夹建在了和libssrc同级,放错了地址,难怪会有问题!
解决:
  • 先是把 jnilibs移动到了正确的问题,即 src - main目录下,与 java同级
    然后重新下载了百度地图的提供的SDK,记得勾选基础定位基础地图这两个包,并点击下载,然后重新放入libsjnilibs
    为了保险,还 clean 清理 和 sync 同步了一下项目
    最后得到了解决!
《第一行代码》11 百度地图实战_第20张图片

问题二:使用百度地图,由于使用了MapView,打开Demo就崩溃

我的情况:
  • 直接崩溃并报错!
java.lang.UnsatisfiedLinkError: Native method not found: com.baidu.mapsdkpla...
解决:
  • 和第一个问题差不多,根据崩溃信息找了半天无果,考虑到是不是引入步骤有问题,仔细检查了一下
    重新下载开发包,把jar和SO库一并替换
    最后得到了解决!

问题三:使用百度地图,位置不准!偏差过大!

我的情况:
  • 其实仔细观察 5-3 和 5-4 的例子,是很有疑问的
    以我使用的模拟器为例
    我首先把自己定位到了 汽车西站地铁口望城坡旁边的肯德基

    《第一行代码》11 百度地图实战_第21张图片

  • 然后我运行程序后,我出现在了离目标地点很远的地方
    这偏差都快1公里了,我勒个去~~~


    《第一行代码》11 百度地图实战_第22张图片
解决:
  • 先来看一张图片


  • 然后修改项目加上一句代码
    调用 LocationClientOption 的setCoorType()传入坐标标准
    由于百度地图默认使用的是 gcj02,这误差不是一般大
    我们改为bd09ll,即百度自己的偏移标准
    private void initLocation(){
        LocationClientOption option = new LocationClientOption();
        option.setScanSpan(5000);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
        option.setIsNeedAddress(true);
        //新增
        // 坐标系,可选,默认gcj02有时会有偏移,改为百度坐标系
        option.setCoorType("bd09ll"); 
        mLocationClient.setLocOption(option);
    }

再次运行一遍:


《第一行代码》11 百度地图实战_第23张图片

随着KFC老头的出现,我们也终于完成了在地图准确显示当前光标的艰巨任务!
百度定位、百度地图的基本使用也告一段落
再见!

你可能感兴趣的:(《第一行代码》11 百度地图实战)