目录
一.踩的一些坑以及解决方法
1.权限声明不要少
2.地图初始化
3.定位问题
(1)监听器注册
(2)定位监听器类MyLocationListener的实现
(3)定位功能的调用
4.android studio连接真机调试问题
二.MainActivity的逻辑代码以及运行结果
官方文档地址:
Android地图SDK | 百度地图API SDK (baidu.com)https://lbsyun.baidu.com/faq/api?title=androidsdk
一.踩的一些坑以及解决方法
1.权限声明不要少
<!-- 访问网络,进行地图相关业务数据请求,包括地图数据,路线规划,POI检索等 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 获取网络状态,根据网络状态切换进行数据请求网络转换 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 读取外置存储。如果开发者使用了so动态加载功能并且把so文件放在了外置存储区域,则需要申请该权限,否则不需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 写外置存储。如果开发者使用了离线地图,并且数据写在外置存储区域,则需要申请该权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 读取设备的电话状态和身份标识 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2.地图初始化
protected void onCreate(Bundle savedInstanceState) {
//定位监视器
super.onCreate(savedInstanceState);
//隐私保护,必须写,不然会报错
SDKInitializer.setAgreePrivacy(getApplicationContext(), true);
SDKInitializer.initialize(getApplicationContext());//一定要先初始化,再加载布局
SDKInitializer.setCoordType(CoordType.BD09LL); //经纬坐标,使用中国国测局的。
setContentView(R.layout.activity_main); //加载布局
在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”
这一段官方文档写的不是很清晰,SDKInitializer在MainActivity类的onCreate方法中实现就可以,但是顺序不要错,初始化语句一定要写在引入布局文件的语句之前,且要在初始化之前加上同意隐私协议的语句,其他文件不需要修改。
3.定位问题
首先要完成权限的声明和地图初始化,这在之前已经陈述过。
其中这两条权限用于定位:
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
定位的逻辑需要用到java多线程编程的知识,为了避免阻塞主线程或造成线程间的等待,通常会将耗时的操作放在后台线程执行 。定位通常是一个耗时的操作,涉及到与设备硬件、网络通信等交互。为了避免主线程的阻塞和界面的卡顿,可以将定位操作放在后台线程中进行,使用多线程的技术实现异步定位。这样,应用程序的主线程可以继续响应用户的操作,同时定位操作在后台线程进行。定位操作完成后,需要将定位结果传递给应用程序进行处理。
(1)监听器注册
public LocationClient mLocationClient= null;
//创建一个定位监听器类对象,MyLocationListener 是一个自定义的定位监听器类,用于接收定位结果的回调。
private MyLocationListener myListener = new MyLocationListener();
try {
//实例化LocationClient 对象并传入应用程序的上下文参数
mLocationClient = new LocationClient(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
//将自定义的定位监听器 myListener 注册到 LocationClient 中
mLocationClient.registerLocationListener(myListener);
这里必须要加上try-catch异常处理机制,不然会报错。
(2)定位监听器类MyLocationListener的实现
//通过继承抽象类BDAbstractListener并重写其onReceieveLocation方法来获取定位数据,并将其传给MapView。
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
int locType = location.getLocType();
Log.d("定位结果错误码", String.valueOf(locType));
//mapView 销毁后不再处理新接收的位置
if (location == null || mMapView == null) { //判断 location 和 mMapView 是否为空来确保在地图视图销毁后不再处理新接收的位置
return;
}
MyLocationData locData = new MyLocationData.Builder() //通过 Builder 模式,设置位置的精度、方向、纬度和经度等属性。
.accuracy(location.getRadius())
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(location.getDirection())
.latitude(location.getLatitude())
.longitude(location.getLongitude())
.build();
baiduMap.setMyLocationData(locData); //将新的位置信息更新到地图上,以显示当前设备的位置
if (isFirstLocate) {
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude()); //根据 BDLocation 对象的经纬度创建一个 LatLng 对象
System.out.println("纬度"+location.getLatitude());
System.out.println("经度"+location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll); //将地图的中心点设置为 ll 所表示的位置
baiduMap.animateMapStatus(update); //动画更新中心点
update = MapStatusUpdateFactory.zoomTo(16f); //将地图的缩放级别设置为 16
baiduMap.animateMapStatus(update); //动画更新缩放级别
isFirstLocate = false;
}
}
}
其中 int locType = location.getLocType();
Log.d("定位结果错误码", String.valueOf(locType));
这两句是打印定位错误码到logcat窗口,去官网对照查表,就可以知道是否定位成功或者发生哪些错误。
Android定位SDK | 百度地图API SDK (baidu.com)https://lbs.baidu.com/faq/api?title=android-locsdk/guide/addition-func/error-code如果返回的是61,161就是定位成功。
(3)定位功能的调用
mLocationClient.start();
注意语句的顺序:
监听器的注册要在定位功能的实现之前,然后启动定位(start),然后调用编写定位参数的方法。
!注意:不要重复编写监听器注册的代码,可能导致定位偏移,博主在onCreate函数中实例化了一次监听器对象,调试程序时候又在编写定位参数的函数中实例化了一次监听器对象,也就是在start()的调用前后各实例化了一次,定位到了一个离博主所在位置搁一条河的小区里面,当博主整理代码时删掉了start函数后面的实例化监听器代码,再次运行之后就定位到了博主所在位置。
4.android studio连接真机调试问题
博主所用为华为nova6手机,harmonyos4.0.0系统,连接真机时与其他手机不同。
要下载华为手机助手:
华为手机助手HiSuite官方下载 | 华为官网 (huawei.com)https://consumer.huawei.com/cn/support/hisuite/用usb连接之后要输入手机上的密码(手机上会自动下载华为手机助手,提供密码)到电脑的华为手机助手。
要开启手机的开发者模式,方法为连续点击设置中的版本号三次,开启usb调试功能,开启ADB,具体操作教程很多,不再赘述。
连接成功后:
在logcat窗口的左上角会显示机型,然后正常run就可以了。
要注意手机的存储空间要充足,否则把软件下载手机上会失败报错
二.MainActivity的逻辑代码以及运行结果
package com.example.mcssignaltest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.app.Application;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
import com.baidu.location.Address;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMapOptions;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.BaiduMap;
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 { //AppCompatActivity是 Activity 类的一个子类,提供了对旧版本 Android 平台的兼容性支持
public LocationClient mLocationClient= null;
private MyLocationListener myListener = new MyLocationListener(); //创建一个定位监听器类对象
private MapView mMapView = null; //百度自定义地图控件
private BaiduMap baiduMap; //地图总控制器
private boolean isFirstLocate = true; //是否是首次定位
private TextView positionText;
@Override
protected void onCreate(Bundle savedInstanceState) {
//定位监视器
super.onCreate(savedInstanceState);
//隐私保护,必须写,不然会报错
SDKInitializer.setAgreePrivacy(getApplicationContext(), true);
LocationClient.setAgreePrivacy(true);
//注册LocationListener监听器
try {
mLocationClient = new LocationClient(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mLocationClient.registerLocationListener(myListener);
SDKInitializer.initialize(getApplicationContext());//一定要先初始化,再加载布局
SDKInitializer.setCoordType(CoordType.BD09LL); //经纬坐标,使用中国国测局的。
setContentView(R.layout.activity_main); //加载布局
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.bmapView);
baiduMap = mMapView.getMap();
positionText = (TextView) findViewById(R.id.position_text_view);
List<String> permissionList = new ArrayList<>();//权限列表,记录未允许的权限
baiduMap.setMyLocationEnabled(true); //开启地图的定位图层
//判断单个权限是否已经允许
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_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
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(); //开始定位,回调定位监听器
initMyLocation(); //调用本地定位方法
}
//权限判断
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, 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:
}
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
//通过继承抽象类BDAbstractListener并重写其onReceieveLocation方法来获取定位数据,并将其传给MapView。
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
int locType = location.getLocType();
Log.d("定位结果错误码", String.valueOf(locType));
//mapView 销毁后不再处理新接收的位置
if (location == null || mMapView == null) { //判断 location 和 mMapView 是否为空来确保在地图视图销毁后不再处理新接收的位置
return;
}
MyLocationData locData = new MyLocationData.Builder() //通过 Builder 模式,设置位置的精度、方向、纬度和经度等属性。
.accuracy(location.getRadius())
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(location.getDirection())
.latitude(location.getLatitude())
.longitude(location.getLongitude())
.build();
baiduMap.setMyLocationData(locData); //将新的位置信息更新到地图上,以显示当前设备的位置
if (isFirstLocate) {
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude()); //根据 BDLocation 对象的经纬度创建一个 LatLng 对象
System.out.println("纬度"+location.getLatitude());
System.out.println("经度"+location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll); //将地图的中心点设置为 ll 所表示的位置
baiduMap.animateMapStatus(update); //动画更新中心点
update = MapStatusUpdateFactory.zoomTo(16f); //将地图的缩放级别设置为 16
baiduMap.animateMapStatus(update); //动画更新缩放级别
isFirstLocate = false;
}
}
}
//通过LocationClient发起定位
private void initMyLocation() {
//通过LocationClientOption设置LocationClient相关参数
LocationClientOption option = new LocationClientOption();
//强制选择高精度定位,三种模式:Hight_Accuracy(高精度)、Battery_Saving(节电模式)、Device_Sensors(传感器模式)
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
option.setOpenGps(true); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000); //设置位置更新间隔,1s一更新
//设置locationClientOption
mLocationClient.setLocOption(option);
}
@Override
protected void onDestroy() {
mLocationClient.stop(); //程序销毁时停止定位,防止消耗电量
baiduMap.setMyLocationEnabled(false);
mMapView.onDestroy();
mMapView = null;
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
}
}