zoukankan      html  css  js  c++  java
  • Android学习笔记之使用LBS实现定位

    PS:最近一直在搞使用LBS实现定位.一般现在涉及到日常生活交易平台的app.貌似都需要使用定位.比如说美团外卖,我请客等app.

    学习内容:

    1.LBS定位的简单介绍.

    2.在Map上添加地图覆盖物+地理编码+反地理编码

    1.LBS定位的简单介绍

     LBS:基站定位.我这里主要还是通过使用百度地图LBS实现定位.使用百度地图LBS实现定位需要做一些相关的准备工作.需要在LBS开放平台上注册自己的AK.有了这个AK.我们的应用才能够去调用百度地图的LBS去实现定位功能.

      百度地图LBS:AK注册地址:http://lbsyun.baidu.com/apiconsole/key.

      我们注册了LBS的账号之后就可以去创建应用的AK了.这里注册需要添加数字签名.数字签名的获取我直接说一种直接了当的方式.就是通过下图去查找.

      黄圈部分就是我们需要添加的数字签名.这是最快也是最直接的方式.还有一种方式是通过cmd的方式进行获取.不过比较麻烦.我一般是使用这种方式去获取的.当输入了数字签名和包名之后.就会出现:

      我们可以看到相关应用对应的AK.有了这个AK之后我们的应用才能够去调用.否则是无法实现定位的.那么这个AK的作用是使用在AndroidManifest文件当中的..

    <application
             <!--name 可以自己命名 
                   value 就是我们获取的AK-->
             <meta-data
                android:name="com.baidu.lbsapi.API_KEY"
                android:value="0FFf1eth8qPtRnGakNXqAXkN"/>
    </application>            

      配置的方式如上.在application标签之间进行添加即可..同时我们还需要添加相关的权限.

    <!-- 百度API所需权限 -->
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.USE_CREDENTIALS" />
        <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
        <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.BROADCAST_STICKY" />
        <uses-permission android:name="android.permission.WRITE_SETTINGS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />

      这是一些配置信息.我们还需要使用相关的jar包.导入了相应的jar包和.so文件之后.我们才能够真正的在自己的应用上进行相关的开发.需要使用的相关文件如下:

      这里我们可以看到使用到了(.so)文件,这个文件其实是动态函数库.只不过是属于C语言层次的.jar包是Java层的一些相关接口.而.so文件则是linux c层的函数库.这里已经不仅仅是涉及到软件层次上的东西了.已经涉及到了Android内部组件的使用.内部硬件的使用自然要通过C语言去调用.因此(.so)文件是必须要使用的.相应的jar包和(.so)文件包大家可以去网上下载.

      那么有了这些基础之后我们就可以真正的去开发我们的定位应用了.

    2.在Map上添加地图覆盖物+地理编码+反地理编码

      需要明确一个概念 Poi:

      BaiDuMap API类中提供了多个类用于我们在地图上添加覆盖物: ArcOptions(弧线形覆盖物),PolygonOptions(多边形覆盖物),TextOptions(文字覆盖物),GroundOverlay(地形图图层覆盖物),PolylineOptions(折线形覆盖物),DotOptions(原点覆盖物),CircleOptions(圆形(空心)覆盖物),这些类都继承与OverlayOptions抽象类

      我们在自定义完这些覆盖物之后,通过使用Overlay中的addOverlay()函数,将相应的覆盖物添加到其中就可以完成在地图上添加覆盖物了.

     那么覆盖物有什么用?查了很多的资料都没有给我一个明确的概念.个人认为比如说显示一个区域范围内的一些相关的数据信息.那么这个范围就可以通过添加覆盖物去指定区域.从而去显示一个区域内有多少数据信息(比如:房产,某一区域的车辆数等等).

      说了这么多.我们就看看如何去添加覆盖物.

      i. 多边形覆盖物(PolygonOptions)

      覆盖物的添加需要经过几个过程,首先我们需要定义一个坐标点,不难理解.就拿多边形覆盖物来说.我们需要定义多个坐标点.这些坐标点的连线才能够构成多边形.构成多边形之后进行一些属性配置.然后使用Overlay中的addOverlay()函数.就能够成功的在地图上添加覆盖物了.

      LatLng pt1 = new LatLng(latitude+0.02,longitude); //参数:经度+纬度
      LatLng pt2 = new LatLng(latitude-0.02,longitude); //构造完多个坐标点..
      List<LatLng> points =new ArrayList<LatLng>();     //保存节点信息.
      PolygonOptions polygonoptions = new PolygonOptions(); //实例化多边形覆盖物对象.
      polygonpoints.points(points);   //添加坐标点
      polygonoptions.fillColor(0xAAFFFF00);  //多边形填充颜色
      polygonpoints.stroke(new Stroke(2,0xAAFFFF00)); //设置多边形边框信息
      Overlay polygon = bdMap.addOverlay(polygonoptions);  //添加覆盖物.

      这样就可以完成在地图上添加覆盖物.我们也可以为这些覆盖物设置相关的监听事件.监听事件的设置如下..每一个覆盖物都属于Marker的点击事件.因此通过setOnMarkerClickListener就可以实现点击时的相关操作.

    bdMap.setOnMarkerClickListener(new OnMarkerClickListener() {
                
                @Override
                public boolean onMarkerClick(Marker arg0) {
                    // TODO Auto-generated method stub
                    final LatLng latLng = arg0.getPosition();
                    if(arg0 == marker1){
                        Toast.makeText(getApplicationContext(), latLng.toString(), Toast.LENGTH_SHORT).show();
                    }
                    return false;
                }
            });

      PolygonOptions的其他函数

     polygonoptions.visiable(boolean visiable); //设置可见性 
     polygonoptions.zIndex(int zIndex) //设置多边形 
     polygonoptions.extraInfo(Bundle extraInfo) // 设置多边形额外信息.

       ii.TextOptions(文字覆盖物)  设置文字覆盖物需要注意文字的颜色,大小,位置和属性

    LatLng latlng = new LatLng(latitude,longitude); 定义坐标点位置
    TextOptions textoptions = new TextOptions(); //实例化对象.
    //rotate为旋转角度. positions为显示的位置. 
    textoptions.bgColor(0xAAFFFF00).fontSize(28).fontColor(0xAAFFFF00).text("").rotate(-30).position(latlng);
    bdMap.addOverlay(textoptions); //在地图中进行添加
    
    //其他函数:
    textoptions.align(int ,int ) 设置文字覆盖物对其方式
    textoptions.extra(Bundle); 
    textoptions.typeface(Typeface); 设置字体
    textoptions.zIndex(int zIndex) 
    textoptions.visiable(boolean visiable)

      iii.GroundOverlay(地形图图层覆盖物)
      地形图图层可以跟随地图进行平移,深入变换,位于地图和标注图之间,不会遮挡标注图信息.定义这个覆盖物的时候,需要指定宽高.API仅仅提供了两种方法去构建:
      1.指定一个(LatLng),再用dimensions方法去指定宽度和高度.
      2.使用positionFromBounds(LatLngBounds bounds) 表示一个地理范围.指定两个角坐标构造一个矩形范围.

      这里使用到了BitmapDescripter,这个是BaiDuMap中的设置定位图标的方法.这个类主要和Overlay进行打交道,可以为Overlay设置图标信息.

        LatLng southwest = new LatLng(latitude - 0.01, longitude - 0.012);//西南  
        LatLng northeast = new LatLng(latitude + 0.01, longitude + 0.012);//东北  
        LatLngBounds bounds =new LatLngBounds.Builder().include(southwest).include(northwest).build();//构建对象.
        BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon); //图标添加.
        GroundOverlayOptions options = new GroundOverlayOptions();
        options.image(bitmap);  //显示的图片
        options.positionFromBounds(bounds); //显示位置
        options.transparency(0.7f); //显示的透明度
        bdMap.addOverlay(options); //添加到地图中

       iv.PolylineOptions(折线覆盖物)

      折线覆盖物和多边形覆盖物的添加基本相同.需要添加多个坐标点..然后在点与点之间画线.

       LatLng pt1 = new LatLng(latitude + 0.01, longitude);
       LatLng pt2 = new LatLng(latitude, longitude - 0.01);
       LatLng pt3 = new LatLng(latitude - 0.01, longitude - 0.01);
       LatLng pt5 = new LatLng(latitude, longitude + 0.01);
       List<LatLng> points = new ArrayList<LatLng>();
       points.add(pt1);
       points.add(pt2);
       points.add(pt3);
       points.add(pt5);
       //
       PolylineOptions polylineOptions = new PolylineOptions();
       polylineOptions.points(points);
       polylineOptions.color(0xFF000000);
       polylineOptions.width(4);
       bdMap.addOverlay(polylineOptions);

      v.DotOptions(原点覆盖物)

      原点覆盖物的添加需要定义圆心坐标,以及半径.

    private void addDotOptions() {
            bdMap.clear();
            DotOptions dotOptions = new DotOptions();
            dotOptions.center(new LatLng(latitude, longitude));// 设置圆心坐标
            dotOptions.color(0XFFfaa755);// 颜色
            dotOptions.radius(25);// 设置半径
            bdMap.addOverlay(dotOptions);
    }

       vi.ArcOptions(弧形覆盖物)

      弧形覆盖物的添加则需要制定弧的起点,中点,终点..制定了这三个点就可以画出相关的弧线.

    private void addArcOptions() {
            bdMap.clear();
            LatLng pt1 = new LatLng(latitude, longitude - 0.01);
            LatLng pt2 = new LatLng(latitude - 0.01, longitude - 0.01);
            LatLng pt3 = new LatLng(latitude, longitude + 0.01);
            ArcOptions arcOptions = new ArcOptions();
            arcOptions.points(pt1, pt2, pt3);// 设置弧线的起点、中点、终点坐标
            arcOptions.width(5);// 线宽
            arcOptions.color(0xFF000000);
            bdMap.addOverlay(arcOptions);
    }

      vii.CircleOptions(圆形(空心)覆盖物)

      圆形空心覆盖物其实和原点覆盖物差不多.只不过一个是实心圆,一个是空心圆.

    private void addCircleOptions() {
            bdMap.clear();
            CircleOptions circleOptions = new CircleOptions();
            circleOptions.center(new LatLng(latitude, longitude));// 设置圆心坐标
            circleOptions.fillColor(0XFFfaa755);// 圆的填充颜色
            circleOptions.radius(150);// 设置半径
            circleOptions.stroke(new Stroke(5, 0xAA00FF00));// 设置边框
            bdMap.addOverlay(circleOptions);

      viii.弹出窗覆盖物.

      弹出窗窗口布局我们可以自己去定义.然后添加到Map当中就可以了.

    private void displayInfoWindow(final LatLng latLng){
            
            // 创建infowindow展示的view
            Button btn = new Button(getApplicationContext());
            btn.setBackgroundResource(R.drawable.popup);
            btn.setText("");
            BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromView(btn);
            // infowindow点击事件
            OnInfoWindowClickListener infoWindowClickListener = new OnInfoWindowClickListener() {
                @Override
                public void onInfoWindowClick() {
                    reverseGeoCode(latLng);
                    //隐藏InfoWindow
                    bdMap.hideInfoWindow();
                }
               };
            // 创建infowindow
            InfoWindow infoWindow = new InfoWindow(bitmapDescriptor, latLng, -47,
                       infoWindowClickListener);
    
              // 显示InfoWindow
            bdMap.showInfoWindow(infoWindow);
        }

      这些都是API为我们提供的相应接口..我们同样可以去自定义样式然后去适配..比如说一个覆盖物的Marker的样式比较复杂..想要使用这个复杂的布局去替换这个bitmap.那么我们就可以将布局转化成bitmap,然后在添加覆盖物的时候..直接添加我们转化的bitmap就可以了.

      IX.实现自定义覆盖物

      首先我们需要定义一个xml文件布局..这个布局可以非常的复杂.但是这个布局的最外层布局只允许是LinearLayout..

     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout 
           xmlns:android="http://schemas.android.com/apk/res/android"
           android:orientation="horizontal"
           android:background="@drawable/popup"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content">
           <ImageView 
               android:layout_width="35dp"
               android:layout_height="35dp"
               android:scaleType="centerCrop"
               android:padding="5dip"
               android:src="@drawable/head_1"/>
    
           <TextView 
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:textColor="@android :color/black"
               android:textSize="20sp"
               android:text="测试"/>
    </LinearLayout>
     

      然后我们把当前这个布局转化成Bitmap.然后在直接定义一个Marker对象.在内部添加Bitmap就可以了.转化成Bitmap的函数其实也并不是特别的复杂.之所以布局文件需要使用LinearLayout进行布局,而不能够使用RelativeLayout.是因为使用了makeMeasureSpec函数.这个函数貌似只对Linearayout有效.这样就可以将我们的xml文件布局转化成bitmap.转化完之后就可以进行添加了..

    private Bitmap getViewBitmap(View addViewContent) {
    
            addViewContent.setDrawingCacheEnabled(true);
    
            addViewContent.measure(
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            addViewContent.layout(0, 0,
                    addViewContent.getMeasuredWidth(),
                    addViewContent.getMeasuredHeight());
    
            addViewContent.buildDrawingCache();
            Bitmap cacheBitmap = addViewContent.getDrawingCache();
            Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
    
            return bitmap;
        }

      说了这么多仅仅是完成了覆盖物的添加,那么如何定位还是一回事..如何根据我们的地理坐标实现定位呢?或者是根据我们的位置获取到地理坐标呢?这就需要使用到地理编码和反地理编码..

      地理编码:将我们当前的地理信息转化成相应的位置.

      反地理编码:将我们当前的坐标转化成地理信息.(注:反地理编码需要在网络链接状态的良好的情况下,才能够实现)

      那么如何去实现呢?其实非常的简单..这个函数就实现了地理信息的编码和反编码.

     private void reverseGeoCode(LatLng latLng){
            //创建地理编码检索实例
            GeoCoder geoCoder = GeoCoder.newInstance();
            //设置地理编码的监听.
            OnGetGeoCoderResultListener listener = new OnGetGeoCoderResultListener() {
                //反地理编码函数的返回结果
                @Override
                public void onGetReverseGeoCodeResult(ReverseGeoCodeResult arg0) {
                    // TODO Auto-generated method stub
                    if(arg0 == null || arg0.error != SearchResult.ERRORNO.NO_ERROR){
                        Toast.makeText(getApplicationContext(), "没有查找到结果", Toast.LENGTH_SHORT).show();
                    }
                    Toast.makeText(getApplicationContext(), "位置:"+arg0.getAddress(), Toast.LENGTH_SHORT).show();
                }
                //地理编码的返回结果
                @Override
                public void onGetGeoCodeResult(GeoCodeResult arg0) {
                    // TODO Auto-generated method stub
                    if(arg0 == null || arg0.error != SearchResult.ERRORNO.NO_ERROR){
                        Toast.makeText(getApplicationContext(), "没有查找到结果", Toast.LENGTH_SHORT).show();
                    }
                }
            };
            //设置地理编码检索监听
            geoCoder.setOnGetGeoCodeResultListener(listener);
            //反地理编码需要传递坐标点参数.
            geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(latLng));
        }

       地理编码和反地理编码都算是很好理解..通过使用API提供的接口.我们就可以轻松实现..通过创建地理编码检索对象,然后为对象设置相关的监听就可以了.地理编码和反地理编码仅仅能够确定我们的位置..但是如果想真正完成定位需要使用到定位的核心类.LocationClient.

      X.LocationClient.

      LocationClient是实现定位的核心类.定位服务的客户端.

            locClient = new LocationClient(this);
            locClient.registerLocationListener(locListener);
            //定位模式 对象实例化
            LocationClientOption option = new LocationClientOption();
            option.setOpenGps(true);     // 打开GPS
            option.setCoorType("bd09ll");// 设置坐标类型
            option.setAddrType("all");     // 地理信息设置
            option.setScanSpan(1000);     // 设置扫描间隔
            
            locClient.setLocOption(option); //添加定位模式 
            locClient.start();                //启动定位  

      只有实例化了LocationClient对象.我们才能够真正的实现定位.实例化对象后.我们需要设置定位的监听.

      定位监听的设置:

    BDLocationListener locListener = new BDLocationListener() {
            
            @Override
            public void onReceivePoi(BDLocation location) {
    
            }
            //定位请求回调函数
            @Override
            public void onReceiveLocation(BDLocation location) {
                if (location == null || bdMap == null) {
                    return;
                }
                // 构造定位数据
                MyLocationData locData = new MyLocationData.Builder()
                        .accuracy(location.getRadius())//
                        .direction(100)// 方向
                        .latitude(location.getLatitude())//
                        .longitude(location.getLongitude())//
                        .build();
                // 设置定位数据
                bdMap.setMyLocationData(locData);
                latitude = location.getLatitude();
                longitude = location.getLongitude();
                // 第一次定位的时候,那地图中心点显示为定位到的位置
                if (isFirstLoc) {
                    isFirstLoc = false;
                    LatLng ll = new LatLng(location.getLatitude(),
                            location.getLongitude());
                    // MapStatusUpdate描述地图将要发生的变化
                    // MapStatusUpdateFactory生成地图将要反生的变化
                    MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(ll);
                    bdMap.animateMapStatus(msu);
                    // bdMap.setMyLocationEnabled(false);
                    Toast.makeText(getApplicationContext(), location.getAddrStr(),
                            Toast.LENGTH_SHORT).show();
                }
            }
        };

      添加了定位的监听以及定位时需要的相关配置参数.就可以真正的实现定位了..

      最后附上一个源代码:

      http://files.cnblogs.com/files/RGogoing/Map.rar





     

     

     

  • 相关阅读:
    19、spring注解学习(声明式事务)——spring注解版声明式事务
    Visual C# 2015调用SnmpSharpNet库实现简单的SNMP元素查询
    SNMP协议交互学习-获取udp的udpindatagrams
    LwIP的SNMP学习笔记
    stm32f407使用Keil uV5建立工程日志
    IP unnumbered interface,某个接口不编号,某个接口不分配IP地址
    OSPFv3与OSPFv2协议的比较
    卫星网络-拓扑优化-文献笔记
    卫星轨道相关笔记SGP4
    [20190226]删除tab$记录的恢复6.txt
  • 原文地址:https://www.cnblogs.com/RGogoing/p/5031108.html
Copyright © 2011-2022 走看看