开头:本次研究此功能是为了完成APP项目中的导航功能和mark标记功能,考虑到GFW问题和baidu map调用速度更快的原因,所以开始了我的百度地图调用初探。
开发学习工具:GPT-4、CSDN
学习链接:Android 程序开发——百度地图的使用(三) 地图定位(定位+跟随+距离测量+地图自适应缩放)_地图根据两点距离 显示地图缩放-CSDN博客android百度地图(实现定位)。六_locationmode.normal-CSDN博客(特别感谢两位大佬的无私分享,让我一步步思路变得越来越清晰,对原理的掌握越来越透彻)
步骤:
一、参考官方开发文档Android地图SDK | 百度地图API SDK
强烈建议开发调用baidumap api的时候先去仔细看看官方的开发文档,会很清晰!
二、具体过程
1、引入SDK那些基础的就不写了,大家可以首选参考官方文档
2、具体写一下代码逻辑
①//在使用SDK各组件之前初始化context信息,传入ApplicationContext
②初始化定位
③请求定位权限
④获取地图控件引用
⑤注册LocationListener监听器
⑥启动定位功能
⑦开启地图定位图层
⑧通过LocationClientOption设置LocationClient相关参数
设置locationClientOption
以上是onCreate中的内容,其中第一步Application需要自己创建一个,LocationListener监听器写在本activity中就可以。两个点注意一下就可以
以下是具体代码
AppLication
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
public class AppLication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext
// 默认本地个性化地图初始化方法
SDKInitializer.initialize(getApplicationContext());
// 自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
// 包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
SDKInitializer.setCoordType(CoordType.BD09LL);
}
}
MapNavigationActivity.class
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
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.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import com.example.outdoor.R;
public class MapNavigationActivity extends AppCompatActivity {
private MapView mMapView = null;
private BaiduMap mBaiduMap;
private LocationClient mLocationClient;
private double user_latitude;
private double user_longitude;
private boolean isSatellite = false; // 用于跟踪当前地图模式
private static final int REQUEST_LOCATION_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SDKInitializer.setAgreePrivacy(getApplicationContext(), true);
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(getApplicationContext());
//自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
//包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
SDKInitializer.setCoordType(CoordType.BD09LL);
//注意该方法要再setContentView方法之前实现
setContentView(R.layout.activity_map_navigation);
LocationClient.setAgreePrivacy(true);
try {
mLocationClient = new LocationClient(this);
} catch (Exception e) {
Toast.makeText(this, "定位初始化失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
Log.e("LocationClientInit", "定位初始化失败", e); // 添加这行日志
}
// 请求定位权限
requestLocationPermission();
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.bmapView);
mBaiduMap = mMapView.getMap();
if (mBaiduMap != null) {
//注册LocationListener监听器
MyLocationListener myLocationListener = new MyLocationListener(mBaiduMap);
mLocationClient.registerLocationListener(myLocationListener);
//启动定位功能
mBaiduMap.setMyLocationEnabled(true);
}
// 设置默认的地图模式为普通地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
//开启地图定位图层
mLocationClient.start();
//通过LocationClientOption设置LocationClient相关参数
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系
option.setScanSpan(1000);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
option.setLocationNotify(true);//可选,默认false,设置是否当GPS有效时按照1S/1次频率输出GPS结果
option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
option.setIgnoreKillProcess(false);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤GPS仿真结果,默认需要
option.setNeedDeviceDirect(true);
//设置locationClientOption
mLocationClient.setLocOption(option);
// 设置按钮的点击事件
ImageButton btnSwitchMap = (ImageButton ) findViewById(R.id.btn_switch_map);
btnSwitchMap.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 切换地图模式
if (isSatellite) {
// 当前是卫星地图,切换到普通地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
} else {
// 当前是普通地图,切换到卫星地图
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
}
isSatellite = !isSatellite; // 更新当前地图模式的跟踪状态
}
});
ImageButton btn_locate = (ImageButton) findViewById(R.id.btn_locate);
btn_locate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 请求定位权限,如果已授权则启动定位客户端
requestLocationPermission();
requestLocationAndUpdateMap();
}
});
}
@Override
protected void onStart() {
super.onStart();
if (mLocationClient != null && !mLocationClient.isStarted()) {
mLocationClient.start();
}
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onDestroy() {
mLocationClient.stop();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
mBaiduMap.setMyLocationEnabled(false);
mMapView = null;
super.onDestroy();
}
private void requestLocationAndUpdateMap() {
if (mLocationClient != null && mLocationClient.isStarted()) {
mLocationClient.requestLocation(); // 请求定位
Toast.makeText(this, "正在请求定位...", Toast.LENGTH_SHORT).show();
} else {
// 需要时,启动定位客户端
mLocationClient.start();
Toast.makeText(this, "启动定位客户端...", Toast.LENGTH_SHORT).show();
}
}
// 定位到用户当前位置
private void showUserLocation() {
LatLng latLng = new LatLng(user_latitude, user_longitude);
MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
mBaiduMap.animateMapStatus(msu);
Toast.makeText(this, "正在定位到设备当前位置...", Toast.LENGTH_SHORT).show();
}
private void requestLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
} else {
// 权限已经被授予
startLocationClient();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限被授予
startLocationClient();
} else {
// 权限被拒绝
Toast.makeText(this, "定位权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
private void startLocationClient() {
if (mLocationClient != null && !mLocationClient.isStarted()) {
mLocationClient.start();
Toast.makeText(this, "定位客户端已启动", Toast.LENGTH_SHORT).show();
}
}
public class MyLocationListener extends BDAbstractLocationListener {
private BaiduMap mBaiduMap; // BaiduMap实例
private boolean isFirstLoc = true; // 标记是否首次定位
private boolean isRequest = false; // 标记是否按需求定位
// 构造函数,传入BaiduMap实例
public MyLocationListener(BaiduMap baiduMap) {
this.mBaiduMap = baiduMap;
}
@Override
public void onReceiveLocation(BDLocation location) {
//mapView 销毁后不在处理新接收的位置
if (location == null || mBaiduMap == null){
Toast.makeText(MapNavigationActivity.this, "定位结果为空或BaiduMap未初始化", Toast.LENGTH_SHORT).show();
return; // 如果定位结果为空或者BaiduMap实例未初始化,则不处理
}
// 显示定位信息
String locInfo = "Lat: " + location.getLatitude() + ", Lng: " + location.getLongitude();
Toast.makeText(MapNavigationActivity.this, locInfo, Toast.LENGTH_LONG).show();
MyLocationData locData = new MyLocationData.Builder()
.accuracy(location.getRadius()) // 设置定位精度
.direction(location.getDirection()) // 设置方向信息,此处设置开发者获取到的方向信息,顺时针0-360
.latitude(location.getLatitude()) // 设置纬度
.longitude(location.getLongitude()) // 设置经度
.build();
mBaiduMap.setMyLocationData(locData);
if (isFirstLoc || isRequest) {
// 将地图中心移动到定位点
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLngZoom(ll, 18f); // 18f是缩放级别
mBaiduMap.animateMapStatus(update);
// 显示弹出覆盖物,这里以显示一个Marker为例
if (isFirstLoc) {
MarkerOptions markerOptions = new MarkerOptions().position(ll)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_xingcheng)); // icon_geo是你的标记图标
mBaiduMap.addOverlay(markerOptions);
}
isFirstLoc = false;
isRequest = false;
}
// 更新用户位置
MapNavigationActivity.this.user_latitude = location.getLatitude();
MapNavigationActivity.this.user_longitude = location.getLongitude();
// 调用showUserLocation方法,定位到用户当前位置
MapNavigationActivity.this.showUserLocation();
}
}
}
最后效果:
要注意:android studio调用百度地图api只能在真机上进行测试,模拟器不行哦,建议是先在编译器中查看Logcat,出现以下报错再去真机测试,会省力不少
2024-02-19 23:30:21.901 23280-23358 AndroidRuntime com.example.outdoor E FATAL EXCEPTION: GLThread 650
Process: com.example.outdoor, PID: 23280
java.lang.IllegalArgumentException: eglChooseConfig failed
at com.baidu.platform.comapi.map.f$a.a(GLRenderControl.java:839)
at com.baidu.platform.comapi.map.f$h.a(GLRenderControl.java:1014)
at com.baidu.platform.comapi.map.f$i.k(GLRenderControl.java:1431)
at com.baidu.platform.comapi.map.f$i.run(GLRenderControl.java:1271)
开发是一件苦尽甘来的事情,如果有帮到您,感谢点赞关注呐~