百度地图开发(Android)

地图在很多应用中都会用到,而百度地图官方的开发者文档很多地方让人摸不着头脑,喵喵喵?而且主要是用在activity中,如果要在fragment中使用地图,还是有一些小坑要注意一下。所以在这里详细记录了一下自己使用百度地图开发的流程。
(悄咪咪说一句,据说高德的开发者文档要写的好一些,但是瞄了一下,其实主要流程都差不多,随缘随缘

1.配置

获取百度地图 SDK开发密钥 点击申请链接添加链接描述。然后访问API控制台页面,若未登录百度账号,将会进入百度账号登录页面。打开API控制台点击创建应用,开始申请开发密钥,应用名称可以随便填,应用类型要选“Android SDK”,然后输入开发版SHA1和发布版SHA1和包名。注册和获取密钥这里不赘述。
添加SDK:jar + so 创建Android项目,在这里下载android定位sdk开发资源添加链接描述,解压后将libs中的jar和so放置到工程中相应的位置。如图:

配置build.gradle文件主要加了sourceSets和implementation files(‘libs/BaiduLBS_Android.jar’)
,注意位置。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "s.wd.myapplication"
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets{
        main{
            jniLibs.srcDir'libs'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:support-v4:27.1.1'
    implementation 'com.google.android.gms:play-services-plus:16.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation files('libs/BaiduLBS_Android.jar')
}

添加AK在Application标签中增加如下代码:

<meta-data
    android:name="com.baidu.lbsapi.API_KEY"
    android:value="AK" >
</meta-data>

添加定位权限声明

  • 在Application标签中声明service组件
<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"> </service>
  • 在Application标签中添加权限
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

如图:
在这里插入图片描述

2.地图显示

先在布局xml文件中添加地图控件

<com.baidu.mapapi.map.MapView
    android:id="@+id/mmap"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</com.baidu.mapapi.map.MapView>

然后在自己的application或者activity或者fragment中初始化 SDK,因为在应用程序创建时初始化 SDK引用的Context 是全局变量,在SDK各功能组件使用之前都需要调用SDKInitializer.initialize(getApplicationContext());因此建议将该方法放在Application的初始化方法中

package s.wd.myapplication.application;

import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
    }
}

接下来在fragment的onCreateView()方法中中实例化地图,并且管理地图的生命周期

public class SportFragment extends Fragment {
    private MapView mMapView;
    private BaiduMap mBaiduMap;
   @Override
   public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
   }
   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_sport, container, false);
        mMapView = (MapView)view.findViewById(R.id.mmap);
        mBaiduMap = mMapView.getMap();
        return view;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //在fragment执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
        mMapView.onDestroy();
    }
    @Override
    public void onResume() {
        super.onResume();
        //在fragment执行onResume时执行mMapView. onResume (),实现地图生命周期管理
        mMapView.onResume();
}
    @Override
    public void onPause() {
        super.onPause();
        //在fragment执行onPause时执行mMapView. onPause (),实现地图生命周期管理
        mMapView.onPause();
    }
}

至此,就可以在fragment中显示百度地图了,效果大致如下
在这里插入图片描述
对导航栏菜单感兴趣的可以看这篇ViewPager+BottomNavigationView+Fragment实现底部导航栏(Android)

3.定位

在onCreate()中声明LocationClient类对象,该对象初始化需传入Context类型参数。推荐使用getApplicationConext()方法获取全进程有效的Context。核心代码段如下:

public LocationClient mLocationClient = null;
private MyLocationListener myListener = new MyLocationListener();
//BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
//原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
public void onCreate() {
    mLocationClient = new LocationClient(getApplicationContext());     
    //声明LocationClient类
    mLocationClient.registerLocationListener(myListener);    
    //注册监听函数
}

在fragment onCreateView中设置mapview的一些地图属性

mMapView = (MapView)view.findViewById(R.id.mmap);
mBaiduMap = mMapView.getMap();
mMapView.showScaleControl(true);//显示比例尺
mMapView.showZoomControls(true);//显示缩放按钮
mMapView.removeViewAt(1);//删除百度地图LoGo

然后配置定位SDK参数,我集成在了自定义的initLocation()函数中

 //配置定位SDK参数
    private void initLocation() {

        LocationClientOption option = new LocationClientOption();
        MyLocationListener myLocationListener = new MyLocationListener();
//注册监听函数
        mLocationClient.registerLocationListener(myLocationListener);
//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备

        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可选,设置定位模式,默认高精度
//LocationMode.Hight_Accuracy:高精度;
//LocationMode. Battery_Saving:低功耗;
//LocationMode. Device_Sensors:仅使用设备;

        option.setCoorType("bd09ll");
//可选,设置返回经纬度坐标类型,默认GCJ02
//GCJ02:国测局坐标;
//BD09ll:百度经纬度坐标;
//BD09:百度墨卡托坐标;
//海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标

        int span=1000;
        option.setScanSpan(span);
//可选,设置发起定位请求的间隔,int类型,单位ms
//如果设置为0,则代表单次定位,即仅定位一次,默认为0
//如果设置非0,需设置1000ms以上才有效

        option.setOpenGps(true);
//可选,设置是否使用gps,默认false
//使用高精度和仅用设备两种定位模式的,参数必须设置为true

        option.setLocationNotify(true);
//可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false

        option.setIgnoreKillProcess(false);
//可选,定位SDK内部是一个service,并放到了独立进程。
//设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
//可选,设置是否收集Crash信息,默认收集,即参数为false

        option.setWifiCacheTimeOut(5*60*1000);
//可选,V7.2版本新增能力
//如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位

        option.setEnableSimulateGps(false);
//可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false
        option.setIsNeedAltitude(false);
//设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化就会主动回调给开发者,该模式下开发者无需再关心定位间隔是多少,定位SDK本身发现位置变化就会及时回调给开发者
        option.setOpenAutoNotifyMode();
//设置打开自动回调位置模式,该开关打开后,期间只要定位SDK检测到位置变化就会主动回调给开发者

        option.setOpenAutoNotifyMode(3000,1, LocationClientOption.LOC_SENSITIVITY_HIGHT);
// 开启定位图层
        mBaiduMap.setMyLocationEnabled(true);
        mLocationClient.setLocOption(option);
//mLocationClient为第二步初始化过的LocationClient对象
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
//开始定位
        mLocationClient.start();
//        option.setIsNeedAddress(true);
//        option.setIsNeedLocationPoiList(true);
    }

然后实现BDAbstractLocationListener接口监听定位,并将监听到的location更新到变量mlocation中,记录当前位置

//实现BDAbstractLocationListener接口
public class MyLocationListener extends BDAbstractLocationListener {
    @Override
    public void onReceiveLocation(BDLocation location) {
        //此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
        //以下只列举部分获取经纬度相关(常用)的结果信息
        //更多结果信息获取说明,请参照类参考中BDLocation类中的说明
        double latitude = location.getLatitude();    //获取纬度信息
        double longitude = location.getLongitude();    //获取经度信息
        float radius = location.getRadius();    //获取定位精度,默认值为0.0f
        String coorType = location.getCoorType();
        //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
        int errorCode = location.getLocType();
        //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
        if (errorCode== BDLocation.TypeGpsLocation
                || errorCode == BDLocation.TypeNetWorkLocation) {
            navigateTo(location);
            mlocation=location;
        }
    }
}

只需用mLocationClient.start()发起定位便能够从BDAbstractLocationListener监听接口中获取定位结果信息。
但是我想要的是除了一进入地图,地图显示的就是自己定位的位置,还有拖动地图后,点击自定义的定位按钮,地图可以回到定位所在地,(你已经是一个成熟的地图了.jpg
先设置自定义的定位图标的点击事件

iv_request= (ImageView) view.findViewById(R.id.iv_request);
iv_request.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(getActivity().getApplicationContext(), "点击事件", Toast.LENGTH_SHORT).show();
        isFirstLoc = true;
        navigateTo(mlocation);
    }
});

其中navigateTo()函数用来更新地图,mlocation为监听到的定位,调用navigateTo(mlocation)即可使地图定位中心显示在mlocation。

private void navigateTo(BDLocation location){
    if(location==null){
        return;
    } else if(isFirstLoc) {
        LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
        MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
        mBaiduMap.animateMapStatus(update);
        //zoom设置缩放等级,值越大,地点越详细
        MapStatus mMapSta0tus = new MapStatus.Builder()
                .target(ll)
                .zoom(19)
                .build();
        //定义MapStatusUpdate对象,以便描述地图状态将要发生的变化
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapSta0tus);
        //改变地图状态
        mBaiduMap.animateMapStatus(mMapStatusUpdate);
        isFirstLoc = false;
    }
    MyLocationData locationData=new MyLocationData.Builder().accuracy(20)//locData.accuracy = location.getRadius();//获取默认误差半径
            //accuracy设置精度圈大小
            //设置开发者获取到的方向信息,顺时针旋转0-360度
            .direction(100).latitude(location.getLatitude()).longitude(location.getLongitude()).build();
    mBaiduMap.setMyLocationData(locationData);
}

因为Android版本越高对应用权限管理就越严格了,所以动态权限获取要求开发者在调用涉及相关权限的代码时,使用系统接口来动态的申请相应权限。其中定位需要动态获取的权限有这几个

权限 内容
Manifest.permission.READ_PHONE_STATE; 获取手机状态
Manifest.permission.ACCESS_COARSE_LOCATION; 获取位置信息
Manifest.permission.ACCESS_FINE_LOCATION; 获取位置信息
Manifest.permission.READ_EXTERNAL_STORAGE; 允许sd卡读权限
Manifest.permission.WRITE_EXTERNAL_STORAGE; 允许sd卡写权限

利用Context.checkSelfPermission接口,定义权限获取码,然后触发系统请求权限弹窗申请权限

List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(Objects.requireNonNull(getActivity()), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
    permissionList.add(Manifest.permission.READ_PHONE_STATE);
}//获取手机状态
if (ContextCompat.checkSelfPermission(Objects.requireNonNull(getActivity()), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}//获取位置信息
if (ContextCompat.checkSelfPermission(Objects.requireNonNull(getActivity()), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}//获取位置信息
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}//读写SD卡
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}//读写SD卡
if (!permissionList.isEmpty()) {
    String[] permissions = permissionList.toArray(new String[permissionList.size()]);
    requestPermissions(permissions, 1);
} else {
    requestLocation();
}

然后处理回调函数onRequestPermissionResult

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
        //requestCode即所声明的权限获取码,在checkSelfPermission时传入

            case 1:
                if (grantResults.length > 0) {//获取到权限
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {//需要确保调用定位SDK相关权限均被授权,否则会引起定位失败

                            Toast.makeText(getActivity(), "发生权限问题", Toast.LENGTH_SHORT).show();
//                            getActivity().finish();
//                            return;
                        }
                    }
                    requestLocation();
                } else {//没有获取到权限
                    Toast.makeText(getActivity(), "发生未知错误,换个新手机试试?", Toast.LENGTH_SHORT).show();
                    getActivity().finish();
                }
                break;
            default:
        }
    }

至此就实现定位功能了,效果大致如下:
在这里插入图片描述


源代码:在fragment中使用百度地图开发
百度开发者文档:添加链接描述

猜你喜欢

转载自blog.csdn.net/tensixchuan/article/details/84781855