android Studio调用百度地图API(实现实时定位+地图模式切换功能)
开头:本次研究此功能是为了完成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)
开发是一件苦尽甘来的事情,如果有帮到您,感谢点赞关注呐~