Android进阶:步骤四:Android 接入百度地图API 基础实现

内容概括:

  1. 注册申请百度地图开发平台账号 这里是地址  如何申请百度地图的账号也有官方文档:在这里
  2. 申请秘钥(AK)、快速获取发布版SHA1和测试版SHA1和包名
  3. (文档里面也有如果创建应用以及申请的教程,但在Android Studio中实现更加简单)
  4. 百度地图的Android Studio的配置
  5. app上实现百度地图的基础功能
  6. app实现切换百度地图的类型(基本和卫星地图)
  7. 实现定位功能
  8. 显示附近商家

一、创建接入百度地图的应用 这里是链接 必须先注册验证成功

1.下面创建应用的界面

2.应用名称随意:我这里填写baiduMap

3.我们选择应用类型为Android SDK 

4.启动服务默认全选就好

5.发布版SHA1和测试版SHA1是什么?怎么简单获取这才是重点

也就是所谓的debug版本和release版本的数字签名,这里不做过多解析,一种加密算法来保证app安全的。

怎么简单获取应用的发布版SHA1和测试版SHA1?

我们打开Android Studio新建一个工程(命名为BaiduMapDemo)

注意红色框框内就是我们这个应用的包名可以修改:我这里写的是

包名:com.demo.baidumap

其他设置默认,创建成功。 

创建好工程后,我们找到Gradle Scripts

1.点击工程下的build.gradle

2.点击屏幕右边隐藏一个侧边区域(Gradle)

3.如果点击后出现的是空白页面点击,蓝色按钮就会出现了

4.那么找到,android包下的signingReport 双击(双击)

双击后再AS的下面Run界面 就会出现

5.我们要的测试版(debug)的SHA1在这里了

这个就是测试版的SHA1:

SHA1: DA:6C:6E:D6:09:98:8B:7D:1C:93:47:03:EC:C2........省略

----------
Variant: debug
Config: debug
Store: /Users/mac/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 91:83:72:3C:C4:74:5A:8D:99:28:59:BE:90:A0:10:C8
SHA1: DA:6C:6E:D6:09:98:8B:7D:1C:93:47:03:EC:C2........省略
Valid until: 2048年3月1日 星期日
----------

6、怎么获取发布版的SHA1

1.Build——>Generate Singed APK

2.默认app即可,next

3.点击create new... 

4.第一个是你存放文件的路径,注意: 后缀名是.keystore (因为它要生成一个.keystore的文件)

password 自定 我这里是android 所有都设置成了android 要记下这个密码,下面的填写任意

填写完成点击OK

 

不需要点击next,这时候你存放的路径就有一个.keystore文件了

6.拿到.keystore文件后,打开终端 

复制这行命令:

keytool -list -v -keystore 

空一个格,将你的.keystore文件拉进终端,就会自动识别它所在的路径

enter键,后提示输入输入密钥库口令:  就是上面那个密码 我这里是android

7.输入密码之后,就会出现发布版的SHA1了

这里我们两个SHA1都拿到了

返回百度地图开发平台的应用创建界面

填写相应的SHA1即可,注意包名千万不能写错,SHA1也是,错了就无法用到百度地图sdk了,注意检查上面是否有遗漏步骤

提交后,你就有一个访问应用的AK了,接下来配置有用 

二、百度地图的Android Studio的配置

1.下载百度地图sdk的jar包这里是地址 在产品下载

这里我们选择自定义下载 我们选择了 你可以全部选择,因为接下来的实现效果只用上这么多所有我们选择了3个基础功能

  1. 基础定位
  2. 基础地图
  3. 计算工具

下载开发包和示例代码和类参考,如要进行深入开发,可以看他的demo

下载完成后解压

这里是百度地图官方的Android Studio配置文档

看不懂我的操作的,可以看看官方的配置文档

1.拷贝BaiduLBS_Android.jar(我们所需要的jar包在⁨BaiduLBS_AndroidSDK_Lib⁩ ▸ ⁨libs⁩里面)放到工程app/libs目录下

找不到libs目录?你可能隐藏了双击上面就会显示出来了

2.在src/main/目录下新建jniLibs目录,并把 armeabi目录和x86目录加载到jniLibs目录中

注意:

这里我只放了armeabi和x86的两个平台的包,而官方建议是放所有的平台,也就是4个,但是每一个体积有4M多,放入更多就会使app的体积变大,所以这里放2个,接下来的操作都是文档里不涉及的,是为了解决放2个而导致的问题的

放四个可以参考官方文档:

这里是百度地图官方的Android Studio配置文档

 3.新增配置解决2个平台引入新的问题

1.打开module的build.gradle

在defaultConfig模块中添加一个ndk模块 如下(目的保证所有的应用只生成两个平台的,不生成其他平台的so不加会导致奔溃)

   compileSdkVersion 27
    defaultConfig {
        applicationId "com.demo.baidumap"
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        
        ndk{
            abiFilters 'armeabi','x86'
        }
   
    }

 2.添加jar文件的依赖 同样是在build.gradle,中

dependencies模块中添加依赖   :implementation files('libs/BaiduLBS_Android.jar') 然后同步一下
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation files('libs/BaiduLBS_Android.jar')
    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'
}

3.应用混淆

集成地图SDK的应用,在打包混淆的时候,需要注意与地图SDK相关的方法不可被混淆。混淆方法如下:

-keep class com.baidu.** {*;}
-keep class mapsdkvi.com.** {*;}    
-dontwarn com.baidu.**

注意:保证百度类不能被混淆,否则会出现网络不可用等运行时异常

复制上面的代码,打开proguard-rules.pro

然后粘贴到末尾,粘贴进去其实并没有生效

接下来,在来到build.gradle里面开启混淆配置

在buildTypes模块中(这是初始的样子)

  buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

修改后 开启混淆配置为true

 buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

之后还有在build.gradle模块中配置我们刚刚上面的keystore文件

1.将.keystore文件拷贝到module目录下

做如下配置:新建signingConfigs模块,并且在buildTypes中引入

下面的keyAlias和密码是你创建.keystore写的

   signingConfigs{
        releaseConfig{
            storeFile file('baidumap.keystore')
            storePassword 'android'
            keyAlias 'android'
            keyPassword 'android'
        }
        
    }
    buildTypes {
        release {
            minifyEnabled true
            signingConfig signingConfigs.releaseConfig
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

注意: 此时可以通过点击右边Gradle,双击工程的android目录下signingReport,就获取到release和debug两个的SHA1,检查一下是否和在百度地图开发平台写的一致,我检查了一遍,发现开发版SHA1的不一致,以signingReport出来的为准.(切记,还有包名不要写错)

包名在build的defaultConfig模块也可以看到:applicationId "com.demo.baidumap"

1.开发版SHA1

2.测试版SHA1

3.包名

三者确保没有写错!

三、 app上实现百度地图的基础功能

1.在module的AndroidManifest.xml配置

(1)在application中添加开发密钥(AK)

示例: 

<application>  
    .....
    <meta-data  
        android:name="com.baidu.lbsapi.API_KEY"  
        android:value="开发者 key" />  
......
</application>

开发者Key是创建应用完成后的访问应用的AK

(2)添加所需权限

注意: 权限应添加在 appliction 之外,如添加到appliction 内部,会导致无法访问网络,不显示地图。

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--获取设备网络状态,禁用后无法获取网络状态-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--网络权限,当禁用后,无法进行检索等相关业务-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!--读取设备硬件信息,统计数据-->
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <!--读取系统信息,包含系统版本等信息,用作统计-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--获取设备的网络状态,鉴权所需网络代理-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--允许sd卡写权限,需写入地图数据,禁用后无法显示地图-->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <!--获取统计数据-->
    <uses-permission android:name="android.permission.CAMERA" />
    <!--使用步行AR导航,配置Camera权限-->

(3) 在布局xml文件中添加地图控件;

acitivity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

</LinearLayout>

(4)新建一个BaiduMapApplication类继承Application 在oncreate方法中写如下:

  • 注意:在SDK各功能组件使用之前都需要调用
  • SDKInitializer.initialize(getApplicationContext());,因此我们建议该方法放在Application的初始化方法中
public class BaiduMapApplication 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);
    }
}

然后到AndroidManifest.xml更改我们的Application (别忘了)

       加入: android:name=".BaiduMapApplication"


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:name=".BaiduMapApplication"
        android:theme="@style/AppTheme">

(5) 创建地图BaiduMapActivity,管理地图生命周期;

public class BaiduMapActivity extends AppCompatActivity {

    private MapView mMapView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取地图控件引用
        mMapView = findViewById(R.id.bmapView);

    }

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

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

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

 完成以上步骤后(打开失败,请仔细检查是否遗漏哪些步骤),运行程序,即可在您的应用中显示地图。 

如果没有遗漏,请检查你的发布版SHA1 和测试版SHA1

(点击Gradle—>android—>双击signingReport在run插入 release和debug的SHA1是否和百度地图创建应用填写的一致)

和包名是否写错

四、调通示例百度Map的Demo

我们下载了BaiduLBS_AndroidSDK_Sample.zip 官方的示例demo

解压后我们把BaiduLoc_AndroidSDK_v7.5_Demo包中Studio版本的BaiduLocDemo的app文件(此时是一个module)导入到我们的工程中

File——>New——>import Module——>选择要导入的module

导入之后,会提示一些错误,比如版本不匹配,或者是compile 要修改成implementation

运行之后你还有可能出现

 Failed to extract native libraries, res=-113的错误

意味着你的模拟器不支持,可以新建一个arm平台的模拟器(不建议非常慢),当然用真机更好

MAC 版android studio 真机调试

注意,版本大于23之后要动态添加权限

五、app实现切换百度地图的类型(基本和卫星地图)

参考百度地图官方切换地图的文档

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapView;

public class BaiduMapActivity extends AppCompatActivity {

    public static final int ITEM_ID_NORMAL_MAP = 101;
    public static final int ITEM_ID_SATELLITE = 102;
    public static final int ITEM_ID_TIME = 103;
    public static final int ITEM_ID_HOT = 104;
    private MapView mMapView = null;
    private BaiduMap mBaiduMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取地图控件引用
        mMapView = findViewById(R.id.bmapView);
        //拿到map对象
        mBaiduMap = mMapView.getMap();
    }

    /**
     * 创建添加菜单
     *
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, ITEM_ID_NORMAL_MAP, 0, "切换成普通地图");
        menu.add(Menu.NONE, ITEM_ID_SATELLITE, 0, "切换成卫星地图");
        menu.add(Menu.NONE, ITEM_ID_TIME, 0, "切换成实时路况图地图");
        menu.add(Menu.NONE, ITEM_ID_HOT, 0, "切换成城市热力地图");
        return super.onCreateOptionsMenu(menu);
    }

    /**
     * 菜单点击事件
     *
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case ITEM_ID_NORMAL_MAP:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
                mBaiduMap.setTrafficEnabled(false);
                mBaiduMap.setBaiduHeatMapEnabled(false);
                break;
            case ITEM_ID_SATELLITE:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
                mBaiduMap.setTrafficEnabled(false);
                mBaiduMap.setBaiduHeatMapEnabled(false);

                break;
            case ITEM_ID_TIME:
                mBaiduMap.setTrafficEnabled(true);
                mBaiduMap.setBaiduHeatMapEnabled(false);
                break;
            case ITEM_ID_HOT:
                mBaiduMap.setBaiduHeatMapEnabled(true);
                mBaiduMap.setTrafficEnabled(false);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

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

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

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

效果: 

六、实现定位功能

参考官方定位文档

1.定位SDK的配置

(1)AndroidManifest.xml中添加定位权限

1.使用定位SDK,需在Application标签中声明service组件,每个App拥有自己单独的定位service,代码如下:

<service
android:name="com.baidu.location.f" 
android:enabled="true" android:process=":remote">
</service>

2. 除添加service组件外,使用定位SDK还需添加如下权限:(注意权限可能和上方之前的有些重复,要去掉)

<!-- 这个权限用于进行网络定位-->
<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.初始化LocationClient类

import android.content.Context;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

/**
 * 实现获取定位信息返回给我们的主Activity
 */
public class LocationInstance {
    /**
     * 第一步:初始化LocationClient类
     */
    public LocationClient mLocationClient;
    private MyLocationListener myListener;

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

        /**
         * 第二步:配置定位SDK参数
         */
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        option.setCoorType("bd09ll");
        option.setScanSpan(1000);
        option.setOpenGps(true);
        option.setLocationNotify(true);
        option.setIgnoreKillProcess(false);
        option.SetIgnoreCacheException(false);
        option.setWifiCacheTimeOut(5 * 60 * 1000);
        option.setEnableSimulateGps(false);
        option.setIsNeedAddress(true);
        mLocationClient.setLocOption(option);
    }

    /**
     * 第三步.实现BDAbstractLocationListener接口
     */
    public static 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类中的说明
        }
    }

    /**
     * 第四步:设置定位的开始和结束的方法
     * 1s定位一次非常耗电的操作
     */
    public void start() {
        mLocationClient.start();
    }

    public void stop() {
        mLocationClient.stop();
    }


}

3.在主界面中拿到实例 

    private LocationInstance mLocationInstance;
    private BDLocation lastLocation;//存放最新一次的位置
....


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        .....
        //初始化定位
        initLocation();
    }
 /**
     * 初始化定位获取实例的方法
     */
    private void initLocation() {
        mLocationInstance = new LocationInstance(
                this,
                new LocationInstance.MyLocationListener() {
                    @Override
                    public void onReceiveLocation(BDLocation location) {
                        super.onReceiveLocation(location);
                        //在这里拿到返回的Location的信息
                        lastLocation=location;
                        Log.d("MAP",
                                location.getAddrStr()+","+"" +
                                        location.getLatitude()+","+
                                        location.getLongitude());
                    }
                });
    }

    /**
     * 开启Location
     */
    @Override
    protected void onStart() {
        mLocationInstance.start();
        super.onStart();
    }

    /**
     * 关闭Location
     */
    @Override
    protected void onStop() {
        mLocationInstance.stop();
        super.onStop();
    }

 4.动态申请权限

此时运行程序,如果是android6.0 sdk23之前都可以显示定位信息

但是:android6.0之后一些权限需要动态申请才行

所有写一个SplashActivity在没进入主界面的时候来获取权限,如果必要的权限没有获取到

就退出应用,并提升用户还有哪些权限没获取;

下次打开之后,只要获取未获取的权限即可,不用重新再获取一遍

参考这篇文章:android6.0之后动态获取权限的封装

打印结果 

com.demo.baidumap D/MAP: 中国湖北省武汉市******,30.501075,114.402673
com.demo.baidumap D/MAP: 中国湖北省武汉市******,30.501075,114.402673
com.demo.baidumap D/MAP: 中国湖北省武汉市******,30.501075,114.402673

3.将定位功能引入我们界面中去:

 显示自己的定位并绘制一个点标记:官方参考文档

   case ITEM_LOCATION:
                //当点击我的定位之后会定位到我的位置,并出现一个方向图片
                mBaiduMap.clear();//每次点击不清除就会叠加
                //定义Maker坐标点(获取经纬度)
                LatLng point = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
                //构建Marker图标

                BitmapDescriptor bitmap = BitmapDescriptorFactory
                        .fromResource(R.drawable.navi_map_gps_locked);
                //构建MarkerOption,用于在地图上添加Marker

                OverlayOptions option = new MarkerOptions()
                        .position(point)
                        .icon(bitmap);
                //在地图上添加Marker,并显示

                mBaiduMap.addOverlay(option);

                //地图可以移动到中心点过去

mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));

                break;

改变地图手势的中心点(地图的中心点)

改变地图手势的中心点,即需要改变地图的中心点,手势旋转等操作是以地图中心点 做旋转的。

在上面的代码最后加上:

mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));

修改默认的缩放级别,在oncreate中添加

        mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15f));

 

这是使用Vysor同手机屏幕在电脑上

旋转手机可以使定位箭头随传感器移动而移动:

参考文档:显示定位文档

1.写一个传感器类:SensorInstantce.java

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

/**
 * 这是传感器的一个类
 * 传出x
 * 设置位置指针的走向
 */
public class SensorInstantce implements SensorEventListener {
    private Context mContext;
    SensorManager mSensorManager;

    public SensorInstantce(Context mContext) {
        this.mContext = mContext;
    }

    public void start() {
        //开启传感器服务
        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager != null) {//防止有些手机不支持
            //拿到sensor对象,方向传感器
            Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
            if (sensor != null) {
                mSensorManager.registerListener((SensorEventListener) this, sensor, SensorManager.SENSOR_DELAY_UI);
            }
        }
    }

    public void stop() {
        //停止服务
        mSensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {
            float x = sensorEvent.values[SensorManager.DATA_X];
            if (mListener != null) {
                //把x传出去
                mListener.onOrientation(x);
            }
        }

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

    /***
     * OnOrientationChangedListener 利用这个方法来将实时改变的x传出去
     */

    private OnOrientationChangedListener mListener;

    public void setOnOrientationChangedListener(OnOrientationChangedListener listener) {
        mListener = listener;
    }

    public static interface OnOrientationChangedListener {
        void onOrientation(float x);
    }
}

2.在BaiduMapAcitivity中

(1)添加成员变量

mIsFirstLocation来实现,第一次如果有定位就直接定位到你当前的定位了

    private SensorInstantce mSensorInstance;//方向传感器对象
    private boolean mIsFirstLocation = true;

(2)oncreate方法中初始化

     mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15f));

        //初始化定位
        initLocation();
        //初始化方向传感器
        initSensorInstance();
        // 开启定位图层
        mBaiduMap.setMyLocationEnabled(true);

这是初始化传感器的方法

 /**
     * 初始化方向传感器,控制定位指针的随传感器的移动而改变
     * 手机移动到哪,图标就指哪个方向
     */
    private void initSensorInstance() {
        mSensorInstance = new SensorInstantce(getApplicationContext());
        mSensorInstance.setOnOrientationChangedListener(new SensorInstantce.OnOrientationChangedListener() {
            @Override
            public void onOrientation(float x) {
                //设置定位图标
                if (lastLocation == null) {//如果上次没有定位,则不需要改变
                    return;
                }
                //实现定位功能
                // 构造定位数据
                MyLocationData locData = new MyLocationData.Builder()
                        .accuracy(lastLocation.getRadius())
                        // 此处设置开发者获取到的方向信息,顺时针0-360
                        .direction(x).latitude(lastLocation.getLatitude())
                        .longitude(lastLocation.getLongitude()).build();

                // 设置定位数据
                mBaiduMap.setMyLocationData(locData);

                // 设置自定义定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)
//                BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory
//                        .fromResource(R.drawable.navi_map_gps_locked);
                //不需要自定义图标
                MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL,
                        true, null);
                mBaiduMap.setMyLocationConfiguration(config);

                /**
                 * 实现以进入地图就定位到我们的位置
                 */
                if (mIsFirstLocation) {
                    mIsFirstLocation = false;
                    //拿到位置
                    LatLng point = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
                    mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));
                }

            }
        });
    }

(3)同样要在Acitivity的onstart 和onStop中开启、关闭 

 /**
     * 开启Location和传感器
     */
    @Override
    protected void onStart() {
        mLocationInstance.start();
        mSensorInstance.start();
        super.onStart();
    }

    /**
     * 关闭Location和传感器
     */
    @Override
    protected void onStop() {
        mLocationInstance.stop();
        mSensorInstance.stop();
        super.onStop();
    }

最后如果出现了两个图标

在定位的菜单的点击事件中,除掉一个图标

            case ITEM_LOCATION:
            。。。。。
                //在地图上添加Marker,并显示
                //将下面那一个图标去掉

//                mBaiduMap.addOverlay(option);

指针方向随手机移动方向改变

 

 七、实现添加附件商家的Marker

百度地图拾取坐标系统的查询

通过拿到的经纬度查询坐标

com.demo.baidumap D/MAP: 中国湖北省武汉市******,30.501075,114.402673(纬度,经度)

longtitute:经度 

Latitude:纬度

 第一:给商家信息做一个分装类

AddressInfo.java

/**
 * 附件商家信息的封装
 */
public class AddressInfo {
    private double latitude;//经度
    private double longtitude;//纬度
    private int imgId;//图片
    private String name;//名称
    private String distance;//距离

    public AddressInfo() {
    }

    public AddressInfo(double latitude, double longtitude, int imgId, String name, String distance) {
        this.latitude = latitude;
        this.longtitude = longtitude;
        this.imgId = imgId;
        this.name = name;
        this.distance = distance;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongtitude() {
        return longtitude;
    }

    public void setLongtitude(double longtitude) {
        this.longtitude = longtitude;
    }

    public int getImgId() {
        return imgId;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDistance() {
        return distance;
    }

    public void setDistance(String distance) {
        this.distance = distance;
    }
}

第二:拿到所有商家信息的集合类


/**
 * 商家数据类
 */
public class AddressInfoLab {

    public static List<AddressInfo> generateDatas() {

        List<AddressInfo> addressInfos = new ArrayList<>();
        // http://api.map.baidu.com/lbsapi/getpoint/index.html
        addressInfos.add(new AddressInfo(30.499861, 114.405871, R.drawable.a1, "关山荷兰风情园",
                "距离209米"));
        addressInfos.add(new AddressInfo(30.50288, 114.402457, R.drawable.a2, "长江职业学院",
                "距离897米"));
        addressInfos.add(new AddressInfo(30.500655, 114.40005, R.drawable.a3, "天龙公寓",
                "距离249米"));
        addressInfos.add(new AddressInfo(30.501277, 114.403679, R.drawable.a4, "三福",
                "距离679米"));
        return addressInfos;
    }
}

第三:在主界面中添加附件商家的菜单按钮

   case ITEM_SHOWSHOP:
                //遍历商家,添加marker
                showShops();
                break;

具体的商家显示的方法: 


    /**
     * 显示商家的方法,并添加marker
     */
    private void showShops() {
        mBaiduMap.clear();//每次点击不清除就会叠加
        //拿到商家信息
        List<AddressInfo> addressInfoList = AddressInfoLab.generateDatas();
        for (AddressInfo addressInfo : addressInfoList) {
            //定义Maker坐标点(获取经纬度)
            LatLng point = new LatLng(addressInfo.getLatitude(), addressInfo.getLongtitude());
            //构建Marker图标
            BitmapDescriptor bitmap = BitmapDescriptorFactory
                    .fromResource(R.drawable.maker);
            //构建MarkerOption,用于在地图上添加Marker

            OverlayOptions option = new MarkerOptions()
                    .position(point)
                    .icon(bitmap);
            //在地图上添加Marker,并显示
            mBaiduMap.addOverlay(option);
        }
        //如果没有地址直接返回
        if (addressInfoList.isEmpty()) {
            return;
        }
        LatLng point = new LatLng(addressInfoList.get(0).getLatitude()
                , addressInfoList.get(0).getLongtitude());

        //让地图自动移动到第一个商家的位置
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLng(point));
    }

 

接下来要处理两个事件

  • 1.商家marker的点击事件
  • 2.点击之后显示商家信息

1.点击事件会弹出一个View

所以建一个布局 item_address_info.xml 用来显示点击商家的信息

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#cc4e5a6b">

    <ImageView
        android:id="@+id/id_marker_img"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_margin="12dp"
        android:background="@drawable/bg_img_icon"
        android:scaleType="fitXY"
        android:src="@drawable/a1" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/id_marker_img"
        android:layout_marginBottom="6dp"
        android:layout_marginEnd="6dp"
        android:layout_marginStart="6dp"
        android:background="#4d5c6c">

        <TextView
            android:id="@+id/id_tx_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14dp"
            tools:text="关山风情园" />

        <TextView
            android:id="@+id/id_tx_distance"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:textSize="14dp"
            tools:text="关山风情园" />
    </FrameLayout>


</RelativeLayout>

2.为了让主界面不那么显得容易,单独建个类来实现View的展示

AddressView.java 商家信息显示的View类

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.demo.baidumap.R;
import com.demo.baidumap.bean.AddressInfo;


/**
 * marker详情布局
 */

public class AddressView extends RelativeLayout {
    private ImageView mIvIcon;
    private TextView mTvName;
    private TextView mTvDistance;


    public AddressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setVisibility(View.GONE);
        LayoutInflater
                .from(context)
                .inflate(
                        R.layout.item_address_info,
                        this);
        mIvIcon = findViewById(R.id.id_marker_img);
        mTvName = findViewById(R.id.id_tx_name);
        mTvDistance = findViewById(R.id.id_tx_distance);

    }

    //对外接受商家信息
    public void setAddressInfo(AddressInfo info) {
        mIvIcon.setImageResource(info.getImgId());
        mTvName.setText(info.getName());
        mTvDistance.setText(info.getDistance());
        setVisibility(View.VISIBLE);
    }
}

3.在主Activity中

1.声明视图对象

   //声明布局对象
 private AddressView mAddressView;

2.oncreate中初始化视图 和点击事件

 //底部商家详情页
        mAddressView = findViewById(R.id.id_address_view);
   //初始化点击事件
        initEvent();

3.点击事件(点击marker和点击地图)两个事件


    public static final String SHOW_INFO = "showInfo";
    private void initEvent() {

        /**
         * 商家marker的点击事件
         */
        mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {

            @Override
            public boolean onMarkerClick(Marker marker) {
                //点击marker之后拿到marker传来的额外信息
                Bundle extraInfo = marker.getExtraInfo();
                AddressInfo addressInfo = (AddressInfo) extraInfo.getSerializable(SHOW_INFO);
                //点击某个marker之后
                mAddressView.setAddressInfo(addressInfo);
                Log.d("TAG", addressInfo.getName());
                //show view
                return false;
            }
        });

        /**
         * 点击地图的事件(让商家信息消失)
         */
        mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                mAddressView.setVisibility(View.GONE);
            }

            @Override
            public boolean onMapPoiClick(MapPoi mapPoi) {
                return false;
            }
        });
    }

在显示商家的方法中将商家的位置放进bundle等待点击事件的触发(获取商家额外信息extraInfo)

  /**
     * 显示商家的方法,并添加marker
     */
    private void showShops() {
    .......
            //构建Marker图标
            BitmapDescriptor bitmap = BitmapDescriptorFactory
                    .fromResource(R.drawable.maker);

            /**
             * 拿到额外信息存到extraInfo里面
             */
            Bundle bundle = new Bundle();
            bundle.putSerializable(SHOW_INFO, addressInfo);
            //并传进去
            //构建MarkerOption,用于在地图上添加Marker
            OverlayOptions option = new MarkerOptions()
                    .position(point)
                    .extraInfo(bundle)//将bundle传进去
                    .icon(bitmap);
         ........
    }

最后还有在显示商家的方法中GONE掉视图

  case ITEM_SHOWSHOP:
                //点击mark gone掉
                mAddressView.setVisibility(View.GONE);
                //遍历商家,添加marker
                showShops();
                break;

最终效果: 

参考:百度地图开发者文档、和帮助与反馈、还有demo来学习百度地图的SDK 

猜你喜欢

转载自blog.csdn.net/qq_17846019/article/details/84025654