个人笔记,仅供参考
1 (LBS)位置服务简介
基于位置的服务,简称 LBS (Location Based Service)
主要工作原理是利用无线电通讯网络或GPS等定位方式来确定移动设备所在位置
即我们通常所说的定位,分两种方式:
一种是通过GPS来定位
基于手机内置的GPS硬件直接和卫星交互来获取当前的经纬度信息,这种定位方式精确度非常高,缺点是只能在室外使用,室内基本上无法接收到卫星的信号
另外一种是通过网络来定位
其工作原理是根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站的距离,再通过三角定位确定出一个大概的位置,这种定位方式精确度一般,优点是室内室外都可以使用
Android API 其实已经对这两种定位做了支持,但是由于某些原因,Google服务在国内无法访问
因此我们只能用到国内第三方公司的SDK
也是主流的两种: 百度地图 和 高德地图
我们就从百度地图开始吧!
2 注册成为百度地图开发者
- 如果以前没百度账号就注册一个
- 如果之前就有则登陆即可 ,百度系的产品账号大部分都是可以通用的
官网地址:https://lbsyun.baidu.com/ - 首页进控制台,然后注册成为开发者
- 注册完以后,可以再回到控制台,你会发现上图左边有个创建应用
没错,我们接下来就开始创建应用
配置并拿到专属于你自己的 API Key
- 以我之前使用过的应用来讲
应用名称: 你可以自定义,比如我这里就叫 MyBaiDuMapDemo
应用类型:点击下拉菜单改为 Android SDK
启动服务:默认不变全选
发布版SHA1: 我这里处于自己测试,发布和开发都用的一个SHA1,如果是正式上线项目,发布版的值允许和开发环境不一样(还请自行网上搜索怎么拿)
开发版SHA1:它是指打包程序时所用签名文件的 SHA1 指纹
(马上会讲到怎么拿这个值)
包名:即你的项目的包名要和这里一致
OK,马上讲一下这个 开发版SHA1怎么拿
- 开始新建项目吧!新建一个名为 BaiDuMapDemo的 Module
- 找到 右侧 Gradle -> 你的项目BaiDuMapDemo -> android -> signingReport 并双击,查看签名信息
- 稍等片刻就会在底部AndroidStudio控制台显示出来你的 SHA1值
- 最后,回到之前创建应用的界面,填入 SHA1值,点击提交,创建成功!
- 那个AK值
bgguVrsdis1ZeNQccqnZXSzP8tN2kYOn
就是我们的API Key
等下需要在项目中用到
现在,我们就可以正式开始百度地图的开发了!
3 SDK下载配置
先下载需要的SDK
由于等下要用到了定位,就先从首页进入定位SDK看看,当然选地图也可以,随便进一个
- 然后会跳到该SDK的详细界面
可以看到,官方文档的 获取密钥、开发指南、类参考都很详细
感兴趣的可以自行深入学习
不过我们点相关下载
,去下载SDK,然后在新的网页点击去下载
- 折腾了半天才到真正下载界面,我勒个去
选中 基础定位 和 基础地图,然后点击下面的下载按钮
下载后会拿到以下几个文件:
BaiduLBS_Android.jar
是Java层需要用到的
其他文件是Native层要用到的
文件夹点进去会看到一些 so文件
so文件
是用C/C++语言进行编写,然后再用NDK编译出来的
当然百度都已经帮我们封装好了,我们只需要关心怎么使用就行
- 在AndroidStudio中把我们的项目切换到project视图下
再把下载的 jar包 复制进项目的libs
文件夹下
然后在main目录下新建一个与java文件夹同级的Directory目录jniLibs
把下载的其余5个文件夹复制进去
- 由于每个新创建的项目中,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定位,则需要用户手动去设置启动
- 高精度模式:允许用户使用 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()
拿到街道等信息
重新运行遍看下效果:
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进行管理,以便资源及时得到释放
重新运行一下程序:
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()
方法
因为将地图移动到当前位置,只需要在第一次定位的时候调用一次就可以了
运行效果:
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条件语句外
因为让地图移动到我们当前位置,只需要定位在第一次定位的时候执行就可以了
但是设备在地图上显示的问题却是跟随设备移动而实时改变的
最后,重新运行一下程序,可以看到一个蓝色小圆点来代表了当前的位置
6 出现过的一些问题
问题一:百度定位,返回经纬度都是4.9E-324
- 第一次用的时候急急躁躁,运行一下定位,我了个去,经纬度一样,还是这种奇怪数据,什么情况?
- 打个断点看了一下
返回信息中报错:
NetWork location failed because baidu location service can not decrypt the request query, please check the so file !
我的情况:
- 查看了一下报错信息,有的说是so文件没加载,还有一些其他说法
我仔细检查了一下步骤是不是哪里出了问题
原来我毛毛躁躁,把jnilibs
文件夹建在了和libs
、src
同级,放错了地址,难怪会有问题!
解决:
- 先是把
jnilibs
移动到了正确的问题,即 src - main目录下,与java
同级
然后重新下载了百度地图的提供的SDK,记得勾选基础定位
和基础地图
这两个包,并点击下载,然后重新放入libs
和jnilibs
为了保险,还 clean 清理 和 sync 同步了一下项目
最后得到了解决!
问题二:使用百度地图,由于使用了MapView,打开Demo就崩溃
我的情况:
- 直接崩溃并报错!
java.lang.UnsatisfiedLinkError: Native method not found: com.baidu.mapsdkpla...
解决:
- 和第一个问题差不多,根据崩溃信息找了半天无果,考虑到是不是引入步骤有问题,仔细检查了一下
重新下载开发包,把jar和SO库一并替换
最后得到了解决!
问题三:使用百度地图,位置不准!偏差过大!
我的情况:
-
其实仔细观察 5-3 和 5-4 的例子,是很有疑问的
以我使用的模拟器为例
我首先把自己定位到了 汽车西站地铁口望城坡旁边的肯德基
-
然后我运行程序后,我出现在了离目标地点很远的地方
这偏差都快1公里了,我勒个去~~~
解决:
-
先来看一张图片
- 然后修改项目加上一句代码
调用 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);
}
再次运行一遍:
随着KFC老头的出现,我们也终于完成了在地图准确显示当前光标的艰巨任务!
百度定位、百度地图的基本使用也告一段落
再见!