优定义网

Android 百度地图开发(二)--- 定位功能之MyLocationOverlay,PopupOverlay的使用

杜明泽 发表于 2018-6-11 21:47:17 | 显示全部楼层 |阅读模式

这一篇文章主要讲解的是百度地图的定位功能,然后还有MyLocationOverlay和PopupOverlay两个地图覆盖物的使用,Overlay是“图层”或“覆盖物”的意思,MyLocationOverlay从名字上面理解就是我的位置图层,他能够实现在地图上显示当前位置的图标以及指南针,MyLocationOverlay只负责显示我的位置,位置数据请使用百度定位SDK获取,将获取的位置数据放在一个LocationData结构中并用该结构设置MyLcationOverlay的数据源,即可创建MyLocationOverlay,PopupOverlay就是弹出窗口图层了,跟PopupWindow类似的东西,下面会介绍他们的使用方法。

定位我们使用的是百度 Android 定位SDKv4.0,我们先了解下定位原理和定位精度

定位原理

使用百度Android定位SDK必须注册GPS和网络使用权限。定位SDK采用GPS、基站、Wi-Fi信号进行定位。当应用程序向定位SDK发起定位请求时,定位SDK会根据应用的定位因素(GPS、基站、Wi-Fi信号)的实际情况(如是否开启GPS、是否连接网络、是否有信号等)来生成相应定位依据进行定位。

用户可以设置满足自身需求的定位依据:

若用户设置GPS优先,则优先使用GPS进行定位,如果GPS定位未打开或者没有可用位置信息,且网络连接正常,定位SDK则会返回网络定位(即Wi-Fi与基站)的最优结果。为了使获得的网络定位结果更加精确,请打开手机的Wi-Fi开关。

1.jpg

定位精度

2.jpg

了解了百度定位的原理和定位精度之后,接下来我们就来使用百度定位SDKv4.0吧

一 . 导入库文件

在使用百度定位SDKv4.0之前,我们要下载最新的库文件,下载地址:点击下载相关库文件,将liblocSDK4.so文件拷贝到libs/armeabi目录下。将locSDK4.0.jar文件拷贝到工程的libs目录下

二 . 布局文件,一个百度地图控件,加一个手动点击实现定位的按钮,放在一个相对布局里面,很简单的布局

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent" >  
  5.   
  6.     <com.baidu.mapapi.map.MapView  
  7.         android:id="@+id/bmapView"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:clickable="true" />  
  11.       
  12.       
  13.      <Button  
  14.          android:id="@+id/request"  
  15.          android:layout_width="wrap_content"  
  16.          android:layout_height="wrap_content"  
  17.          android:layout_alignParentRight="true"  
  18.          android:layout_alignParentTop="true"  
  19.          android:layout_marginRight="10dp"  
  20.          android:layout_marginTop="10dip"  
  21.          android:background="@drawable/custom_loc"  />  
  22.   
  23. </RelativeLayout>  
复制代码

三 . 界面MainActivity代码,先贴上,然后适当讲解相关代码,我注释也比较清楚

  1. package com.example.baidumapdemo;  
  2.   
  3. import android.app.Activity;  
  4. import android.graphics.Bitmap;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.view.View.MeasureSpec;  
  10. import android.view.View.OnClickListener;  
  11. import android.widget.Button;  
  12. import android.widget.TextView;  
  13. import android.widget.Toast;  
  14.   
  15. import com.baidu.location.BDLocation;  
  16. import com.baidu.location.BDLocationListener;  
  17. import com.baidu.location.LocationClient;  
  18. import com.baidu.location.LocationClientOption;  
  19. import com.baidu.mapapi.BMapManager;  
  20. import com.baidu.mapapi.MKGeneralListener;  
  21. import com.baidu.mapapi.map.LocationData;  
  22. import com.baidu.mapapi.map.MKEvent;  
  23. import com.baidu.mapapi.map.MapController;  
  24. import com.baidu.mapapi.map.MapView;  
  25. import com.baidu.mapapi.map.MyLocationOverlay;  
  26. import com.baidu.mapapi.map.PopupClickListener;  
  27. import com.baidu.mapapi.map.PopupOverlay;  
  28. import com.baidu.platform.comapi.basestruct.GeoPoint;  
  29.   
  30. public class MainActivity extends Activity {  
  31.     private Toast mToast;  
  32.     private BMapManager mBMapManager;  
  33.     private MapView mMapView = null;  
  34.     private MapController mMapController = null;  
  35.       
  36.     /**
  37.      * 定位SDK的核心类
  38.      */  
  39.     private LocationClient mLocClient;  
  40.     /**
  41.      * 用户位置信息  
  42.      */  
  43.     private LocationData mLocData;  
  44.     /**
  45.      * 我的位置图层
  46.      */  
  47.     private LocationOverlay myLocationOverlay = null;  
  48.     /**
  49.      * 弹出窗口图层
  50.      */  
  51.     private PopupOverlay mPopupOverlay  = null;  
  52.       
  53.     private boolean isRequest = false;//是否手动触发请求定位  
  54.     private boolean isFirstLoc = true;//是否首次定位  
  55.       
  56.     /**
  57.      * 弹出窗口图层的View
  58.      */  
  59.     private View mPopupView;  
  60.     private BDLocation location;  
  61.   
  62.     @Override  
  63.     protected void onCreate(Bundle savedInstanceState) {  
  64.         super.onCreate(savedInstanceState);  
  65.         //使用地图sdk前需先初始化BMapManager,这个必须在setContentView()先初始化  
  66.         mBMapManager = new BMapManager(this);  
  67.          
  68.         //第一个参数是API key,  
  69.         //第二个参数是常用事件监听,用来处理通常的网络错误,授权验证错误等,你也可以不添加这个回调接口  
  70.         mBMapManager.init("7ae13368159d6a513eaa7a17b9413b4b", new MKGeneralListenerImpl());  
  71.         setContentView(R.layout.activity_main);  
  72.          
  73.         //点击按钮手动请求定位  
  74.         ((Button) findViewById(R.id.request)).setOnClickListener(new OnClickListener() {  
  75.               
  76.             @Override  
  77.             public void onClick(View v) {  
  78.                 requestLocation();  
  79.             }  
  80.         });  
  81.          
  82.         mMapView = (MapView) findViewById(R.id.bmapView); //获取百度地图控件实例  
  83.         mMapController = mMapView.getController(); //获取地图控制器  
  84.         mMapController.enableClick(true);   //设置地图是否响应点击事件  
  85.         mMapController.setZoom(14);   //设置地图缩放级别  
  86.         mMapView.setBuiltInZoomControls(true);   //显示内置缩放控件  
  87.          
  88.         mMapView.setTraffic(true);  //设置交通信息图  
  89. //        mMapView.setSatellite(true);  //设置卫星图  
  90. //        mMapController.setOverlooking(-45);  //设置地图俯视角度 ,范围:0~ -45  
  91.          
  92.          
  93.         mPopupView = LayoutInflater.from(this).inflate(R.layout.pop_layout, null);  
  94.          
  95.         //实例化弹出窗口图层  
  96.         mPopupOverlay = new PopupOverlay(mMapView ,new PopupClickListener() {  
  97.               
  98.             /**
  99.              * 点击弹出窗口图层回调的方法
  100.              */  
  101.             @Override  
  102.             public void onClickedPopup(int arg0) {  
  103.                 //隐藏弹出窗口图层  
  104.                 mPopupOverlay.hidePop();  
  105.             }  
  106.         });  
  107.          
  108.          
  109.         //实例化定位服务,LocationClient类必须在主线程中声明  
  110.         mLocClient = new LocationClient(getApplicationContext());  
  111.         mLocClient.registerLocationListener(new BDLocationListenerImpl());//注册定位监听接口  
  112.          
  113.         /**
  114.          * LocationClientOption 该类用来设置定位SDK的定位方式。
  115.          */  
  116.         LocationClientOption option = new LocationClientOption();  
  117.         option.setOpenGps(true); //打开GPRS  
  118.         option.setAddrType("all");//返回的定位结果包含地址信息  
  119.         option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02  
  120.         option.setPriority(LocationClientOption.GpsFirst); // 设置GPS优先  
  121.         option.setScanSpan(5000); //设置发起定位请求的间隔时间为5000ms  
  122.         option.disableCache(false);//禁止启用缓存定位  
  123. //      option.setPoiNumber(5);    //最多返回POI个数     
  124. //      option.setPoiDistance(1000); //poi查询距离         
  125. //      option.setPoiExtraInfo(true);  //是否需要POI的电话和地址等详细信息         
  126.         mLocClient.setLocOption(option);  //设置定位参数  
  127.          
  128.          
  129.         mLocClient.start();  // 调用此方法开始定位  
  130.          
  131.         //定位图层初始化  
  132.         myLocationOverlay = new LocationOverlay(mMapView);  
  133.          
  134.          
  135.         //实例化定位数据,并设置在我的位置图层  
  136.         mLocData = new LocationData();  
  137.         myLocationOverlay.setData(mLocData);  
  138.          
  139.         //添加定位图层  
  140.         mMapView.getOverlays().add(myLocationOverlay);  
  141.          
  142.         //修改定位数据后刷新图层生效  
  143.         mMapView.refresh();  
  144.          
  145.          
  146.     }  
  147.       
  148.       
  149.     /**
  150.      * 定位接口,需要实现两个方法
  151.      * @author xiaanming
  152.      *
  153.      */  
  154.     public class BDLocationListenerImpl implements BDLocationListener {  
  155.   
  156.         /**
  157.          * 接收异步返回的定位结果,参数是BDLocation类型参数
  158.          */  
  159.         @Override  
  160.         public void onReceiveLocation(BDLocation location) {  
  161.             if (location == null) {  
  162.                 return;  
  163.             }  
  164.               
  165.             StringBuffer sb = new StringBuffer(256);  
  166.               sb.append("time : ");  
  167.               sb.append(location.getTime());  
  168.               sb.append("\nerror code : ");  
  169.               sb.append(location.getLocType());  
  170.               sb.append("\nlatitude : ");  
  171.               sb.append(location.getLatitude());  
  172.               sb.append("\nlontitude : ");  
  173.               sb.append(location.getLongitude());  
  174.               sb.append("\nradius : ");  
  175.               sb.append(location.getRadius());  
  176.               if (location.getLocType() == BDLocation.TypeGpsLocation){  
  177.                    sb.append("\nspeed : ");  
  178.                    sb.append(location.getSpeed());  
  179.                    sb.append("\nsatellite : ");  
  180.                    sb.append(location.getSatelliteNumber());  
  181.                    } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){  
  182.                    sb.append("\naddr : ");  
  183.                    sb.append(location.getAddrStr());  
  184.                 }   
  185.            
  186.               Log.e("log", sb.toString());  
  187.               
  188.               
  189.             MainActivity.this.location = location;  
  190.               
  191.             mLocData.latitude = location.getLatitude();  
  192.             mLocData.longitude = location.getLongitude();  
  193.             //如果不显示定位精度圈,将accuracy赋值为0即可  
  194.             mLocData.accuracy = location.getRadius();  
  195.             mLocData.direction = location.getDerect();  
  196.               
  197.             //将定位数据设置到定位图层里  
  198.             myLocationOverlay.setData(mLocData);  
  199.             //更新图层数据执行刷新后生效  
  200.             mMapView.refresh();  
  201.               
  202.               
  203.             if(isFirstLoc || isRequest){  
  204.                 //将给定的位置点以动画形式移动至地图中心  
  205.                 mMapController.animateTo(new GeoPoint(  
  206.                         (int) (location.getLatitude() * 1e6), (int) (location  
  207.                                 .getLongitude() * 1e6)));  
  208.                 showPopupOverlay(location);  
  209.                 isRequest = false;  
  210.             }  
  211.             isFirstLoc = false;  
  212.               
  213.         }  
  214.   
  215.         /**
  216.          * 接收异步返回的POI查询结果,参数是BDLocation类型参数
  217.          */  
  218.         @Override  
  219.         public void onReceivePoi(BDLocation poiLocation) {  
  220.               
  221.         }  
  222.   
  223.     }  
  224.       
  225.       
  226.   
  227.     //继承MyLocationOverlay重写dispatchTap方法  
  228.     private class LocationOverlay extends MyLocationOverlay{  
  229.   
  230.         public LocationOverlay(MapView arg0) {  
  231.             super(arg0);  
  232.         }  
  233.   
  234.          
  235.         /**
  236.          * 在“我的位置”坐标上处理点击事件。
  237.          */  
  238.         @Override  
  239.         protected boolean dispatchTap() {  
  240.             //点击我的位置显示PopupOverlay  
  241.             showPopupOverlay(location);  
  242.             return super.dispatchTap();  
  243.         }  
  244.          
  245.     }  
  246.       
  247.       
  248.     /**
  249.      * 显示弹出窗口图层PopupOverlay
  250.      * @param location
  251.      */  
  252.     private void showPopupOverlay(BDLocation location){  
  253.          TextView popText = ((TextView)mPopupView.findViewById(R.id.location_tips));  
  254.          popText.setText("[我的位置]\n" + location.getAddrStr());  
  255.          mPopupOverlay.showPopup(getBitmapFromView(popText),  
  256.                     new GeoPoint((int)(location.getLatitude()*1e6), (int)(location.getLongitude()*1e6)),  
  257.                     15);  
  258.            
  259.     }  
  260.       
  261.       
  262.     /**
  263.      * 手动请求定位的方法
  264.      */  
  265.     public void requestLocation() {  
  266.         isRequest = true;  
  267.          
  268.         if(mLocClient != null && mLocClient.isStarted()){  
  269.             showToast("正在定位......");  
  270.             mLocClient.requestLocation();  
  271.         }else{  
  272.             Log.d("log", "locClient is null or not started");  
  273.         }  
  274.     }  
  275.       
  276.       
  277.       
  278.      /**  
  279.      * 显示Toast消息  
  280.      * @param msg  
  281.      */   
  282.     private void showToast(String msg){   
  283.         if(mToast == null){   
  284.             mToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);   
  285.         }else{   
  286.             mToast.setText(msg);   
  287.             mToast.setDuration(Toast.LENGTH_SHORT);  
  288.         }   
  289.         mToast.show();   
  290.     }   
  291.       
  292.     /**
  293.      * 将View转换成Bitmap的方法
  294.      * @param view
  295.      * @return
  296.      */  
  297.     public static Bitmap getBitmapFromView(View view) {  
  298.         view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  
  299.         view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());  
  300.         view.buildDrawingCache();  
  301.         Bitmap bitmap = view.getDrawingCache();  
  302.         return bitmap;  
  303.     }  
  304.       
  305.       
  306.       
  307.       
  308.       
  309.     /**
  310.      * 常用事件监听,用来处理通常的网络错误,授权验证错误等
  311.      * @author xiaanming
  312.      *
  313.      */  
  314.     public class MKGeneralListenerImpl implements MKGeneralListener{  
  315.   
  316.         /**
  317.          * 一些网络状态的错误处理回调函数
  318.          */  
  319.         @Override  
  320.         public void onGetNetworkState(int iError) {  
  321.             if (iError == MKEvent.ERROR_NETWORK_CONNECT) {  
  322.                 showToast("您的网络出错啦!");  
  323.             }  
  324.         }  
  325.   
  326.         /**
  327.          * 授权错误的时候调用的回调函数
  328.          */  
  329.         @Override  
  330.         public void onGetPermissionState(int iError) {  
  331.             if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {  
  332.                 showToast("API KEY错误, 请检查!");  
  333.             }  
  334.         }  
  335.          
  336.     }  
  337.       
  338.     @Override  
  339.     protected void onResume() {  
  340.         //MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause()  
  341.         mMapView.onResume();  
  342.         super.onResume();  
  343.     }  
  344.   
  345.   
  346.   
  347.     @Override  
  348.     protected void onPause() {  
  349.         //MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause()  
  350.         mMapView.onPause();  
  351.         super.onPause();  
  352.     }  
  353.   
  354.     @Override  
  355.     protected void onDestroy() {  
  356.         //MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy()  
  357.         mMapView.destroy();  
  358.          
  359.         //退出应用调用BMapManager的destroy()方法  
  360.         if(mBMapManager != null){  
  361.             mBMapManager.destroy();  
  362.             mBMapManager = null;  
  363.         }  
  364.          
  365.         //退出时销毁定位  
  366.         if (mLocClient != null){  
  367.             mLocClient.stop();  
  368.         }  
  369.          
  370.         super.onDestroy();  
  371.     }  
  372.   
  373.       
  374.       
  375. }  
复制代码

LocationClient 定位SDK的核心类,LocationClient类必须在主线程中声明。需要Context类型的参数。Context需要时全进程有效的context,推荐用getApplicationConext获取全进程有效的context,我们调用registerLocationListener(BDLocationListener)方法来注册定位监听接口,BDLocationListener里面有两个方法,onReceiveLocation()(接收异步返回的定位结果),onReceivePoi()(接收异步返回的POI查询结果,POI是“Point of Interest”的缩写,可以翻译成“信息点”,每个POI包含四方面信息,名称、类别、经度、纬度、附近的酒店、饭店,商铺等信息。我们可以叫它为“导航地图信息”,导航地图数据是整个导航产业的基石),我们这里只需要重写onReceiveLocation就行了

BDLocation 封装了定位SDK的定位结果,在BDLocationListener的onReceive方法中获取。通过该类用户可以获取error code,位置的坐标,精度半径,地址等信息,对于其getLocType ()方法获取的error code一些情况

61 : GPS定位结果

62 : 扫描整合定位依据失败。此时定位结果无效。

63 : 网络异常,没有成功向服务器发起请求。此时定位结果无效。

65 : 定位缓存的结果。

66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果

67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果

68 : 网络连接失败时,查找本地离线定位时对应的返回结果

161: 表示网络定位结果

162~167: 服务端定位失败

LocationClientOption 用来设置定位SDK的定位方式,比如设置打开GPS,设置是否需要地址信息,设置发起定位请求的间隔时间等等,参数设置完后调用LocationClient 的setLocOption方法

LocationOverlay  MyLocationOverlay的子类,重写里面的dispatchTap()方法,显示弹出窗口图层PopupOverlay,调用mMapView.getOverlays().add(myLocationOverlay)就将我的位置图层添加到地图里面

PopupOverlay 弹出图层,这个类还是比较简单,里面只有三个方法,hidePop() (隐藏弹出图层)showPopup(Bitmap pop, GeoPoint point, int yOffset) (显示弹出图层)和showPopup显示多张图片的重载方法,由于showPopup方法只接受Bitmap对象,所以我们必须将我们的弹出图层View对象转换成Bitmap对象,我们调用getBitmapFromView方法就实现这一转换

BDLocationListener接口的onReceiveLocation(BDLocation location) 方法我还要重点讲解下,我们会发现onReceiveLocation方法会反复执行,他执行的间隔跟LocationClientOption类的setScanSpan()方法设定的值有关,我们设定的是5000毫秒,则onReceiveLocation方法每隔5秒执行一次,注意,当我们设定的值大于1000(ms),定位SDK内部使用定时定位模式。调用requestLocation( )后,每隔设定的时间,定位SDK就会进行一次定位。

如果定位SDK根据定位依据发现位置没有发生变化,就不会发起网络请求,返回上一次定位的结果;如果发现位置改变,就进行网络请求进行定位,得到新的定位结果。如果你只需要定位一次的话,这个设置小于1000,或者不用设置就可以了,定时定位时,调用一次requestLocation,会定时监听到定位结果

四 . 在运行程序之前,我们还必须在AndroidManifest.xml进行相关配置和权限的声明

在application标签中声明service组件,每个app拥有自己单独的定位service

  1. <service  
  2.             android:name="com.baidu.location.f"  
  3.             android:enabled="true"  
  4.             android:process=":remote" >  
  5.         </service>  
复制代码

声明相关的使用权限

  1. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
  2. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
  3. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
  5. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />  
  6. <uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  7. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  8. <uses-permission android:name="android.permission.INTERNET" />  
  9. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  10. <uses-permission android:name="android.permission.READ_LOGS" />  
复制代码

五 . 运行结果

3.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精华推荐
  • 一个人开始废掉的3种迹象

    一个人开始废掉的3种迹象

  • 从零到60秒的惬意冰镇啤酒

    从零到60秒的惬意冰镇啤酒

  • 马云、马化腾、王石都弃之不用的人,有一个共同点

    马云、马化腾、王石都弃之不用的人,有一个

  • 哥特式高迪凳子

    哥特式高迪凳子

  • 千亿小米,雷军逆袭

    千亿小米,雷军逆袭

  • 她一战赚了几十亿,她说:世界上最好的生意有三种

    她一战赚了几十亿,她说:世界上最好的生意有

  • 雷军:合伙人比制度更重要!

    雷军:合伙人比制度更重要!

  • 一个美美的令人喜欢的自行车铃

    一个美美的令人喜欢的自行车铃

QQ客服热线
QQ:1090281100 周一至周日:09:00 - 21:00
WeChat:dianlingkeji
Email:kaixin1069@vip.qq.com

优定义logo

勿要吝啬你无形资产,请为创新续源,知识、点子、灵感、经验、需求等均是创新源泉,你不经意的一句话将是另一个人的灵感。明天的明天,还有明天,我们应该把握今天,每一个今天,都有一个新的事物在出现,今天的漠视明天的落后,不浪费每一个学习的时刻,学习助力非凡。

技术支持 Discuz! X3.4 - 3.5 beta © 2001-2018 Comsenz Inc.

小黑屋|手机版|优定义 ( 粤ICP备16085288号-2 )|申请友链|网站地图

粤公网安备 44011102001144 号 GMT+8, 2018-10-17 12:16 , Processed in 0.096278 second(s), 29 queries .

快速回复 返回顶部 返回列表